Merge branch 'maint'

* Bug 711440 - Tab labels have different background colour than containing gui element
* Bug 434462 - register color don't work correct with system theme color
* Add scrub function for (business) lots to eliminate unneeded lot links
* Rewrite invoice payment logic to use lot links only when absolutely needed
* Bug 684719 - Man pages for gnc-fq-* perl scripts
This commit is contained in:
Geert Janssens 2014-09-02 22:59:41 +02:00
commit 4ecc4cb7d0
35 changed files with 1455 additions and 583 deletions

View File

@ -154,6 +154,7 @@ void gnc_payment_acct_tree_row_activated_cb (GtkWidget *widget, GtkTreePath *pat
GtkTreeViewColumn *column, PaymentWindow *pw);
void gnc_payment_leave_amount_cb (GtkWidget *widget, GdkEventFocus *event,
PaymentWindow *pw);
void gnc_payment_window_fill_docs_list (PaymentWindow *pw);
static void
@ -161,6 +162,7 @@ gnc_payment_window_refresh_handler (GHashTable *changes, gpointer data)
{
PaymentWindow *pw = data;
gnc_payment_window_fill_docs_list (pw);
pw->post_acct = gnc_account_select_combo_fill (pw->post_combo, pw->book, pw->acct_types, pw->acct_commodities);
}
@ -324,6 +326,8 @@ gnc_payment_dialog_highlight_document (PaymentWindow *pw)
lot = (GNCLot *) g_value_get_pointer (&value);
g_value_unset (&value);
if (!lot)
continue; /* Lot has been deleted behind our back... */
invoice = gncInvoiceGetInvoiceFromLot (lot);
if (!invoice)
@ -340,7 +344,7 @@ gnc_payment_dialog_highlight_document (PaymentWindow *pw)
}
}
static void
void
gnc_payment_window_fill_docs_list (PaymentWindow *pw)
{
GtkListStore *store;
@ -1102,37 +1106,13 @@ gnc_ui_payment_new (GncOwner *owner, QofBook *book)
}
// ////////////////////////////////////////////////////////////
static gboolean isAssetLiabType(GNCAccountType t)
{
switch (t)
{
case ACCT_TYPE_RECEIVABLE:
case ACCT_TYPE_PAYABLE:
return FALSE;
default:
return (xaccAccountTypesCompatible(ACCT_TYPE_ASSET, t)
|| xaccAccountTypesCompatible(ACCT_TYPE_LIABILITY, t));
}
}
static gboolean isAPARType(GNCAccountType t)
{
switch (t)
{
case ACCT_TYPE_RECEIVABLE:
case ACCT_TYPE_PAYABLE:
return TRUE;
default:
return FALSE;
}
}
static void increment_if_asset_account (gpointer data,
gpointer user_data)
{
int *r = user_data;
const Split *split = data;
const Account *account = xaccSplitGetAccount(split);
if (isAssetLiabType(xaccAccountGetType(account)))
if (xaccAccountIsAssetLiabType(xaccAccountGetType(account)))
++(*r);
}
static int countAssetAccounts(SplitList* slist)
@ -1147,7 +1127,7 @@ static gint predicate_is_asset_account(gconstpointer a,
{
const Split *split = a;
const Account *account = xaccSplitGetAccount(split);
if (isAssetLiabType(xaccAccountGetType(account)))
if (xaccAccountIsAssetLiabType(xaccAccountGetType(account)))
return 0;
else
return -1;
@ -1157,7 +1137,7 @@ static gint predicate_is_apar_account(gconstpointer a,
{
const Split *split = a;
const Account *account = xaccSplitGetAccount(split);
if (isAPARType(xaccAccountGetType(account)))
if (xaccAccountIsAPARType(xaccAccountGetType(account)))
return 0;
else
return -1;

View File

@ -49,17 +49,6 @@ typedef enum
GNCENTRY_NUM_REGISTER_TYPES
} GncEntryLedgerType;
typedef struct entry_ledger_colors
{
guint32 header_bg_color;
guint32 primary_bg_color;
guint32 secondary_bg_color;
guint32 primary_active_bg_color;
guint32 secondary_active_bg_color;
} GncEntryLedgerColors;
#define ENTRY_IACCT_CELL "inv-account"
#define ENTRY_BACCT_CELL "bill-account"
#define ENTRY_ACTN_CELL "action"

View File

@ -36,15 +36,6 @@
#include "gncEntryLedgerP.h"
#include "gncEntryLedgerModel.h"
static GncEntryLedgerColors reg_colors =
{
0x96B183,
0xBFDEB9,
0xF6FFDA,
0xFFEF98,
0xFFEF98,
};
/** Private Interfaces ***********************************************/
@ -926,43 +917,85 @@ static CellIOFlags get_qty_io_flags (VirtualLocation virt_loc, gpointer user_dat
/* GET BG_COLORS */
static guint32
gnc_entry_ledger_get_color_internal (VirtualLocation virt_loc,
GncEntryLedger *ledger,
const guint32 *color_table,
gboolean foreground)
{
const char *cursor_name;
VirtualCell *vcell;
gboolean is_current;
guint32 colorbase = 0; /* By default return background colors */
if (foreground)
colorbase = COLOR_UNKNOWN_FG; /* a bit of enum arithmetic */
if (!ledger)
return color_table[colorbase + COLOR_UNKNOWN_BG];
if (gnc_table_virtual_location_in_header (ledger->table, virt_loc))
return color_table[colorbase + COLOR_HEADER_BG];
vcell = gnc_table_get_virtual_cell (ledger->table, virt_loc.vcell_loc);
if (!vcell || !vcell->cellblock)
return color_table[colorbase + COLOR_UNKNOWN_BG];
if ((virt_loc.phys_col_offset < vcell->cellblock->start_col) ||
(virt_loc.phys_col_offset > vcell->cellblock->stop_col))
return color_table[colorbase + COLOR_UNKNOWN_BG];
is_current = virt_cell_loc_equal (ledger->table->current_cursor_loc.vcell_loc,
virt_loc.vcell_loc);
if (is_current)
return vcell->start_primary_color ?
color_table[colorbase + COLOR_PRIMARY_BG_ACTIVE] :
color_table[colorbase + COLOR_SECONDARY_BG_ACTIVE];
return vcell->start_primary_color ?
color_table[colorbase + COLOR_PRIMARY_BG] : color_table[colorbase + COLOR_SECONDARY_BG];
}
static guint32
gnc_entry_ledger_get_fg_color (VirtualLocation virt_loc,
gpointer user_data)
{
GncEntryLedger *ledger = user_data;
return gnc_entry_ledger_get_color_internal (virt_loc, ledger, reg_colors_default, TRUE);
}
static guint32
gnc_entry_ledger_get_gtkrc_fg_color (VirtualLocation virt_loc,
gpointer user_data)
{
GncEntryLedger *ledger = user_data;
return gnc_entry_ledger_get_color_internal (virt_loc, ledger, reg_colors_gtkrc, TRUE);
}
static guint32
gnc_entry_ledger_get_bg_color (VirtualLocation virt_loc,
gboolean *hatching, gpointer user_data)
{
GncEntryLedger *ledger = user_data;
VirtualCell *vcell;
guint32 bg_color;
gboolean is_current;
if (hatching)
*hatching = FALSE;
bg_color = 0xffffff; /* white */
return gnc_entry_ledger_get_color_internal (virt_loc, ledger, reg_colors_default, FALSE);
}
if (!ledger) return bg_color;
static guint32
gnc_entry_ledger_get_gtkrc_bg_color (VirtualLocation virt_loc,
gboolean *hatching, gpointer user_data)
{
GncEntryLedger *ledger = user_data;
if (gnc_table_virtual_location_in_header (ledger->table, virt_loc))
return reg_colors.header_bg_color;
if (hatching)
*hatching = FALSE;
vcell = gnc_table_get_virtual_cell (ledger->table, virt_loc.vcell_loc);
if (!vcell || !vcell->cellblock)
return bg_color;
if ((virt_loc.phys_col_offset < vcell->cellblock->start_col) ||
(virt_loc.phys_col_offset > vcell->cellblock->stop_col))
return bg_color;
is_current = virt_cell_loc_equal
(ledger->table->current_cursor_loc.vcell_loc, virt_loc.vcell_loc);
if (is_current)
return vcell->start_primary_color ?
reg_colors.primary_active_bg_color :
reg_colors.secondary_active_bg_color;
return vcell->start_primary_color ?
reg_colors.primary_bg_color : reg_colors.secondary_bg_color;
return gnc_entry_ledger_get_color_internal (virt_loc, ledger, reg_colors_gtkrc, FALSE);
}
/* SAVE CELLS */
@ -1214,9 +1247,18 @@ static void gnc_entry_ledger_model_new_handlers (TableModel *model,
};
unsigned int i;
gnc_table_model_set_default_fg_color_handler
(model, gnc_entry_ledger_get_fg_color);
gnc_table_model_set_fg_color_handler
(model, gnc_entry_ledger_get_gtkrc_fg_color, "gtkrc");
gnc_table_model_set_default_bg_color_handler
(model, gnc_entry_ledger_get_bg_color);
gnc_table_model_set_bg_color_handler
(model, gnc_entry_ledger_get_gtkrc_bg_color, "gtkrc");
for (i = 0; i < (sizeof(models) / sizeof(*models)); i++)
{

View File

@ -4208,6 +4208,30 @@ xaccAccountTypesValid(void)
return mask;
}
gboolean xaccAccountIsAssetLiabType(GNCAccountType t)
{
switch (t)
{
case ACCT_TYPE_RECEIVABLE:
case ACCT_TYPE_PAYABLE:
return FALSE;
default:
return (xaccAccountTypesCompatible(ACCT_TYPE_ASSET, t)
|| xaccAccountTypesCompatible(ACCT_TYPE_LIABILITY, t));
}
}
gboolean xaccAccountIsAPARType(GNCAccountType t)
{
switch (t)
{
case ACCT_TYPE_RECEIVABLE:
case ACCT_TYPE_PAYABLE:
return TRUE;
default:
return FALSE;
}
}
gboolean
xaccAccountIsPriced(const Account *acc)
{

View File

@ -943,6 +943,16 @@ gboolean xaccAccountTypesCompatible (GNCAccountType parent_type,
* root account types are stripped. */
guint32 xaccAccountTypesValid(void);
/** Convenience function to check if the account is a valid
* Asset or Liability type, but not a business account type
* (meaning not an Accounts Payable/Accounts Receivable). */
gboolean xaccAccountIsAssetLiabType(GNCAccountType t);
/** Convenience function to check if the account is a valid
* business account type
* (meaning an Accounts Payable/Accounts Receivable). */
gboolean xaccAccountIsAPARType(GNCAccountType t);
/** @} */

View File

@ -22,6 +22,7 @@ libgncmod_engine_la_SOURCES = \
Scrub.c \
Scrub2.c \
Scrub3.c \
ScrubBusiness.c \
Split.c \
TransLog.c \
Transaction.c \
@ -70,6 +71,7 @@ gncinclude_HEADERS = \
Scrub.h \
Scrub2.h \
Scrub3.h \
ScrubBusiness.h \
Split.h \
TransLog.h \
Transaction.h \

View File

@ -529,7 +529,10 @@ xaccTransScrubImbalance (Transaction *trans, Account *root,
/* Return immediately if things are balanced. */
if (xaccTransIsBalanced (trans))
{
LEAVE ("transaction is balanced");
return;
}
currency = xaccTransGetCurrency (trans);
@ -626,7 +629,7 @@ xaccTransScrubImbalance (Transaction *trans, Account *root,
imbal_list = xaccTransGetImbalance (trans);
if (!imbal_list)
{
LEAVE("()");
LEAVE("transaction is balanced");
return;
}

View File

@ -344,7 +344,7 @@ merge_splits (Split *sa, Split *sb)
}
gboolean
xaccScrubMergeSubSplits (Split *split)
xaccScrubMergeSubSplits (Split *split, gboolean strict)
{
gboolean rc = FALSE;
Transaction *txn;
@ -352,7 +352,7 @@ xaccScrubMergeSubSplits (Split *split)
GNCLot *lot;
const GncGUID *guid;
if (FALSE == is_subsplit (split)) return FALSE;
if (strict && (FALSE == is_subsplit (split))) return FALSE;
txn = split->parent;
lot = xaccSplitGetLot (split);
@ -392,7 +392,7 @@ restart:
}
gboolean
xaccScrubMergeLotSubSplits (GNCLot *lot)
xaccScrubMergeLotSubSplits (GNCLot *lot, gboolean strict)
{
gboolean rc = FALSE;
SplitList *node;
@ -404,7 +404,7 @@ restart:
for (node = gnc_lot_get_split_list(lot); node; node = node->next)
{
Split *s = node->data;
if (!xaccScrubMergeSubSplits(s)) continue;
if (!xaccScrubMergeSubSplits(s, strict)) continue;
rc = TRUE;
goto restart;

View File

@ -53,7 +53,7 @@
* not in a lot will be used to close the oldest open lot(s).
* If there are no open lots, a new lot will be started.
* By trying to close the oldest lots, this effectively
* implements a FIFO acounting policy.
* implements a FIFO accounting policy.
*/
void xaccAccountAssignLots (Account *acc);
@ -89,16 +89,26 @@ void xaccLotScrubDoubleBalance (GNCLot *lot);
* the same lot, or in no lot. Note that, by definition, all
* subsplits belong to the same transaction.
*
* There are two ways to find matching subsplits. The first
* way will consider splits to be subsplits only if they
* are explicitly marked as such while splitting the original
* split. Set strict to TRUE for this matching algorhythm.
*
* The second way is more relaxed. It will consider any two
* splits that happen to be part of the same lot and the
* same transaction to be subsplits. Set strict to FALSE for
* this matching algorhythm.
*
* The routine returns TRUE if a merger was performed, else
* it returns FALSE.
*
* The xaccScrubMergeTransSubSplits() routine does the same, except
* that it does it for all of the splits in the transaction.
* The xaccScrubMergeLotSubSplits() routine does the same, except
* that it does it for all of the splits in the lot.
*/
gboolean xaccScrubMergeSubSplits (Split *split);
gboolean xaccScrubMergeLotSubSplits (GNCLot *lot);
gboolean xaccScrubMergeSubSplits (Split *split, gboolean strict);
/** The xaccScrubMergeLotSubSplits() routine does the same as
* the xaccScrubMergSubSplits, except that it does it
* for all of the splits in the lot.
*/
gboolean xaccScrubMergeLotSubSplits (GNCLot *lot, gboolean strict);
#endif /* XACC_SCRUB2_H */
/** @} */

View File

@ -96,7 +96,7 @@ xaccScrubLot (GNCLot *lot)
acc = gnc_lot_get_account (lot);
pcy = gnc_account_get_policy(acc);
xaccAccountBeginEdit(acc);
xaccScrubMergeLotSubSplits (lot);
xaccScrubMergeLotSubSplits (lot, TRUE);
/* If the lot balance is zero, we don't need to rebalance */
lot_baln = gnc_lot_get_balance (lot);
@ -132,7 +132,7 @@ rethin:
xaccLotFill (lot);
/* Make sure there are no subsplits. */
splits_deleted = xaccScrubMergeLotSubSplits (lot);
splits_deleted = xaccScrubMergeLotSubSplits (lot, TRUE);
}
/* Now re-compute cap gains, and then double-check that.

View File

@ -25,7 +25,7 @@
@{ */
/** @file Scrub3.h
* @brief Hiogh-Level API for imposing Lot constraints
* @brief High-Level API for imposing Lot constraints
* @author Created by Linas Vepstas Sept 2003
* @author Copyright (c) 2003 Linas Vepstas <linas@linas.org>
*/
@ -44,7 +44,7 @@
* self-consistent and properly balanced, and fixes it if its not.
* This is an important routine to call if the amount of any split
* in the lot is changed. That's because (obviously) changing
* split values is gaurenteed to throw off lot balances.
* split values is guaranteed to throw off lot balances.
* This routine may end up closing the lot, or at least trying
* to. It will also cause cap gains to be recomputed.
*

333
src/engine/ScrubBusiness.c Normal file
View File

@ -0,0 +1,333 @@
/********************************************************************\
* ScrubBusiness.h -- Cleanup functions for the business objects. *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
\********************************************************************/
/** @file ScrubBusiness.h
* @brief Cleanup functions for business objects
* @author Created by Geert Janssens August 2014
* @author Copyright (c) 2014 Geert Janssens <geert@kobaltwit.be>
*
* Provides the high-level API for checking and repairing ('scrubbing
* clean') the various data objects used by the business functions.*/
#include "config.h"
#include <glib.h>
#include <glib/gi18n.h>
#include "gnc-engine.h"
#include "gnc-lot.h"
#include "policy-p.h"
#include "Account.h"
#include "gncInvoice.h"
#include "Scrub2.h"
#include "ScrubBusiness.h"
#include "Transaction.h"
static QofLogModule log_module = GNC_MOD_LOT;
// A helper function that takes two splits. If the splits are of opposite sign
// it reduces the biggest split to have the same value (but with opposite sign)
// of the smaller split.
// To make sure everything still continues to balance in addition a "remainder" split
// will be created that will be added to the same lot and transaction as the biggest
// split.
// The opposite sign restriction is because that's the only scenario that makes sense
// in the context of scrubbing business lots below.
// If we created new splits, return TRUE, otherwise FALSE
static gboolean reduce_biggest_split (Split *splitA, Split *splitB)
{
gnc_numeric valA = xaccSplitGetValue (splitA);
gnc_numeric valB = xaccSplitGetValue (splitB);
if (gnc_numeric_compare (gnc_numeric_abs (valA), gnc_numeric_abs (valB)) >= 0)
return gncOwnerReduceSplitTo (splitA, gnc_numeric_neg (valB));
else
return gncOwnerReduceSplitTo (splitB, gnc_numeric_neg (valA));
}
// Attempt to eliminate or reduce the lot link splits (ll_*_split)
// between from_lot and to_lot. To do so this function will attempt
// to move a payment split from from_lot to to_lot in order to
// balance the lot link split that will be deleted.
// To ensure everything remains balanced at most
// min (val-ll-*-split, val-pay-split) (in absolute values) can be moved.
// If any split involved has a larger value, it will be split in two
// and only the part matching the other splits' value will be used.
// The leftover splits are kept in the respective transactions/lots.
// A future scrub action can still act on those if needed.
//
// Note that this function assumes that ll_from_split and ll_to_split are
// of opposite sign. The calling function should check this.
static gboolean
scrub_other_link (GNCLot *from_lot, Split *ll_from_split,
GNCLot *to_lot, Split *ll_to_split)
{
Split *real_from_split; // This refers to the split in the payment lot representing the payment itself
gnc_numeric from_val, real_from_val, to_val;
gboolean modified = FALSE;
Transaction *ll_txn = xaccSplitGetParent (ll_to_split);
// Per iteration we can only scrub at most max (val-doc-split, val-pay-split)
// So split the bigger one in two if needed and continue with the equal valued splits only
// The remainder is added to the lot link transaction and the lot to keep everything balanced
// and will be processed in a future iteration
modified = reduce_biggest_split (ll_from_split, ll_to_split);
// Next we have to find the original payment split so we can
// add (part of) it to the document lot
real_from_split = gncOwnerFindOffsettingSplit (from_lot, xaccSplitGetValue (ll_from_split));
if (!real_from_split)
return modified; // No usable split in the payment lot
// Here again per iteration we can only scrub at most max (val-other-pay-split, val-pay-split)
// So split the bigger one in two if needed and continue with the equal valued splits only
// The remainder is added to the lot link transaction and the lot to keep everything balanced
// and will be processed in a future iteration
modified = reduce_biggest_split (real_from_split, ll_from_split);
// Once more check for max (val-doc-split, val-pay-split), and reduce if necessary.
// It may have changed while looking for the real payment split
modified = reduce_biggest_split (ll_from_split, ll_to_split);
// At this point ll_to_split and real_from_split should have the same value
// If not, flag a warning and skip to the next iteration
to_val = xaccSplitGetValue (ll_to_split);
from_val = xaccSplitGetValue (ll_from_split);
real_from_val = xaccSplitGetValue (real_from_split);
if (!gnc_numeric_equal (real_from_val, to_val))
{
// This is unexpected - write a warning message and skip this split
PWARN("real_from_val and to_val differ. "
"This is unexpected! Skip scrubbing of real_from_split %p against ll_to_split %p.", real_from_split, ll_to_split);
return modified;
}
// Now do the actual split dance
// - move real payment split to doc lot
// - delete both lot link splits from the lot link transaction
gnc_lot_add_split (to_lot, real_from_split);
xaccTransBeginEdit (ll_txn);
xaccSplitDestroy (ll_to_split);
xaccSplitDestroy (ll_from_split);
xaccTransCommitEdit (ll_txn);
// Cleanup the lots
xaccScrubMergeLotSubSplits (to_lot, FALSE);
xaccScrubMergeLotSubSplits (from_lot, FALSE);
return TRUE; // We did change splits/transactions/lots...
}
static gboolean
gncScrubLotLinks (GNCLot *scrub_lot)
{
gboolean modified = FALSE, restart_needed = FALSE;
SplitList *sls_iter = NULL;
scrub_start:
restart_needed = FALSE;
// Iterate over all splits in the lot
for (sls_iter = gnc_lot_get_split_list (scrub_lot); sls_iter; sls_iter = sls_iter->next)
{
Split *sl_split = sls_iter->data;
Transaction *ll_txn = NULL; // ll_txn = "Lot Link Transaction"
SplitList *lts_iter = NULL;
if (!sl_split)
continue; // next scrub lot split
// Only lot link transactions need to be scrubbed
ll_txn = xaccSplitGetParent (sl_split);
if (!ll_txn)
{
// Ooops - the split doesn't belong to any transaction !
// This is not expected so issue a warning and continue with next split
PWARN("Encountered a split in a business lot that's not part of any transaction. "
"This is unexpected! Skipping split %p.", sl_split);
continue;
}
if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
continue; // next scrub lot split
// Iterate over all splits in the lot link transaction
for (lts_iter = xaccTransGetSplitList (ll_txn); lts_iter; lts_iter = lts_iter->next)
{
Split *ll_txn_split = lts_iter->data; // These all refer to splits in the lot link transaction
GNCLot *remote_lot = NULL; // lot at the other end of the lot link transaction
gboolean sl_is_doc_lot, rl_is_doc_lot;
if (!ll_txn_split)
continue; // next lot link transaction split
// Skip the split in the lot we're currently scrubbing
if (sl_split == ll_txn_split)
continue; // next lot link transaction split
// Only splits of opposite sign can be scrubbed
if (gnc_numeric_positive_p (xaccSplitGetValue (sl_split)) ==
gnc_numeric_positive_p (xaccSplitGetValue (ll_txn_split)))
continue; // next lot link transaction split
// Find linked lot via split
remote_lot = xaccSplitGetLot (ll_txn_split);
if (!remote_lot)
{
// This is unexpected - write a warning message and skip this split
PWARN("Encountered a Lot Link transaction with a split that's not in any lot. "
"This is unexpected! Skipping split %p from transaction %p.", ll_txn_split, ll_txn);
continue;
}
sl_is_doc_lot = (gncInvoiceGetInvoiceFromLot (scrub_lot) != NULL);
rl_is_doc_lot = (gncInvoiceGetInvoiceFromLot (remote_lot) != NULL);
// Depending on the type of lots we're comparing, we need different actions
// - Two document lots (an invoice and a credit note):
// Special treatment - look for all document lots linked via ll_txn
// and update the memo to be of more use to the uses.
// - Two payment lots:
// (Part of) the link will be eliminated and instead (part of)
// one payment will be added to the other lot to keep the balance.
// If the payments are not equal in abs value part of the bigger payment
// will be moved to the smaller payment's lot.
// - A document and a payment lot:
// (Part of) the link will be eliminated and instead (part of) the real
// payment will be added to the document lot to handle the payment.
if (sl_is_doc_lot && rl_is_doc_lot)
gncOwnerSetLotLinkMemo (ll_txn);
else if (!sl_is_doc_lot && !rl_is_doc_lot)
{
gint cmp = gnc_numeric_compare (gnc_numeric_abs (xaccSplitGetValue (sl_split)),
gnc_numeric_abs (xaccSplitGetValue (ll_txn_split)));
if (cmp >= 0)
restart_needed = scrub_other_link (scrub_lot, sl_split, remote_lot, ll_txn_split);
else
restart_needed = scrub_other_link (remote_lot, ll_txn_split, scrub_lot, sl_split);
}
else
{
GNCLot *doc_lot = sl_is_doc_lot ? scrub_lot : remote_lot;
GNCLot *pay_lot = sl_is_doc_lot ? remote_lot : scrub_lot;
Split *ll_doc_split = sl_is_doc_lot ? sl_split : ll_txn_split;
Split *ll_pay_split = sl_is_doc_lot ? ll_txn_split : sl_split;
// Ok, let's try to move a payment from pay_lot to doc_lot
restart_needed = scrub_other_link (pay_lot, ll_pay_split, doc_lot, ll_doc_split);
}
// If we got here, the splits in our lot and ll_txn have been severely mixed up
// And our iterator lists are probably no longer valid
// So let's start over
if (restart_needed)
{
modified = TRUE;
goto scrub_start;
}
}
}
return modified;
}
gboolean
gncScrubBusinessLot (GNCLot *lot)
{
gboolean splits_deleted = FALSE;
Account *acc;
gchar *lotname=NULL;
if (!lot) return FALSE;
lotname = g_strdup (gnc_lot_get_title (lot));
ENTER ("(lot=%p) %s", lot, lotname ? lotname : "(no lotname)");
acc = gnc_lot_get_account (lot);
if (acc)
xaccAccountBeginEdit(acc);
// Scrub lot links.
// They should only remain when two document lots are linked together
xaccScrubMergeLotSubSplits (lot, FALSE);
splits_deleted = gncScrubLotLinks (lot);
// If lot is empty now, delete it
if (0 == gnc_lot_count_splits (lot))
{
PINFO("All splits were removed from lot, deleting");
gnc_lot_destroy (lot);
}
if (acc)
xaccAccountCommitEdit(acc);
LEAVE ("(lot=%s, deleted=%d)", lotname ? lotname : "(no lotname)", splits_deleted);
g_free (lotname);
return splits_deleted;
}
/* ============================================================== */
void
gncScrubBusinessAccountLots (Account *acc)
{
LotList *lots, *node;
if (!acc) return;
if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
ENTER ("(acc=%s)", xaccAccountGetName(acc));
xaccAccountBeginEdit(acc);
lots = xaccAccountGetLotList(acc);
for (node = lots; node; node = node->next)
{
GNCLot *lot = node->data;
if (lot)
gncScrubBusinessLot (lot);
}
g_list_free(lots);
xaccAccountCommitEdit(acc);
LEAVE ("(acc=%s)", xaccAccountGetName(acc));
}
/* ============================================================== */
static void
lot_scrub_cb (Account *acc, gpointer data)
{
if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
gncScrubBusinessAccountLots (acc);
}
void
gncScrubBusinessAccountTreeLots (Account *acc)
{
if (!acc) return;
gnc_account_foreach_descendant(acc, lot_scrub_cb, NULL);
gncScrubBusinessAccountLots (acc);
}
/* ========================== END OF FILE ========================= */

View File

@ -0,0 +1,79 @@
/********************************************************************\
* ScrubBusiness.h -- Cleanup functions for the business objects. *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
\********************************************************************/
/** @addtogroup Engine
@{ */
/** @addtogroup Scrub
@{ */
/** @file ScrubBusiness.h
* @brief Cleanup functions for business objects
* @author Created by Geert Janssens August 2014
* @author Copyright (c) 2014 Geert Janssens <geert@kobaltwit.be>
*/
#ifndef GNC_SCRUBBUSINESS_H
#define GNC_SCRUBBUSINESS_H
#include "gnc-engine.h"
/** @name Cleanup functions for business objects
* Provides the high-level API for checking and repairing ('scrubbing
* clean') the various data objects used by the business functions.
@{ */
/** The gncScrubBusinessLot() function makes sure that the indicated
* lot has all the correct properties required for a lot used in
* the business features.
*
* Currently this function only does one thing: eliminate lot link
* transactions between invoice lots and payment lots (which were
* generated by GnuCash versions 2.6.0-2.6.3). Lot links
* between invoices and credit notes will still remain.
*
* Scrubbing the lot may cause subsplits to be merged together,
* i.e. for splits to be deleted. This routine returns true if
* any splits were modified or deleted.
*/
gboolean gncScrubBusinessLot (GNCLot *lot);
/** The gncScrubBusinessAccountLots() function will call
* gncScrubBusinessLot() on each lot in the given account.
*
* This routine is the primary routine for ensuring that the
* lot structure of every lot of a business account is in good
* order.
*/
void gncScrubBusinessAccountLots (Account *acc);
/** The gncScrubBusinessAccountTreeLots() function will call
* gncScrubBusinessAccountLots() on each lot in the given account
* and its sub accounts.
*
* This routine is the primary routine for ensuring that the
* lot structure of every lot of a business account is in good
* order.
*/
void gncScrubBusinessAccountTreeLots (Account *acc);
/** @} */
#endif /* GNC_SCRUBBUSINESS_H */
/** @} */
/** @} */

View File

@ -43,7 +43,6 @@
#include "Split.h"
#include "AccountP.h"
#include "Scrub.h"
#include "Scrub3.h"
#include "TransactionP.h"
#include "TransLog.h"
#include "cap-gains.h"

View File

@ -213,7 +213,7 @@ void xaccTransRollbackEdit (Transaction *trans);
/** The xaccTransIsOpen() method returns TRUE if the transaction
is open for editing. Otherwise, it returns false.
XXX this routne should probably be deprecated. its, umm,
XXX this routine should probably be deprecated. its, umm,
hard to imagine legitimate uses (but it is used by
the import/export code for reasons I can't understand.)
*/

View File

@ -309,6 +309,8 @@ gnc_lot_free(GNCLot* lot)
priv->is_closed = TRUE;
/* qof_instance_release (&lot->inst); */
g_object_unref (lot);
LEAVE();
}
void
@ -635,6 +637,7 @@ gnc_lot_remove_split (GNCLot *lot, Split *split)
}
gnc_lot_commit_edit(lot);
qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_MODIFY, NULL);
LEAVE("removed from lot");
}
/* ============================================================== */

View File

@ -44,14 +44,17 @@
#include "gncVendorP.h"
#include "gncInvoice.h"
#include "gnc-commodity.h"
#include "Transaction.h"
#include "Scrub2.h"
#include "Split.h"
#include "Transaction.h"
#include "engine-helpers.h"
#define _GNC_MOD_NAME GNC_ID_OWNER
#define GNC_OWNER_ID "gncOwner"
static QofLogModule log_module = GNC_MOD_ENGINE;
GncOwner * gncOwnerNew (void)
{
GncOwner *o;
@ -834,9 +837,368 @@ gncOwnerCreatePaymentLot (const GncOwner *owner, Transaction *txn,
return payment_lot;
}
typedef enum
{
is_equal = 8,
is_more = 4,
is_less = 2,
is_pay_split = 1
} split_flags;
Split *gncOwnerFindOffsettingSplit (GNCLot *lot, gnc_numeric target_value)
{
SplitList *ls_iter = NULL;
Split *best_split = NULL;
gnc_numeric best_val = { 0, 1};
gint best_flags = 0;
if (!lot)
return NULL;
for (ls_iter = gnc_lot_get_split_list (lot); ls_iter; ls_iter = ls_iter->next)
{
Split *split = ls_iter->data;
Transaction *txn;
gnc_numeric split_value;
gint new_flags = 0;
gint val_cmp = 0;
if (!split)
continue;
txn = xaccSplitGetParent (split);
if (!txn)
{
// Ooops - the split doesn't belong to any transaction !
// This is not expected so issue a warning and continue with next split
PWARN("Encountered a split in a payment lot that's not part of any transaction. "
"This is unexpected! Skipping split %p.", split);
continue;
}
// Check if this split has the opposite sign of the target value we want to offset
split_value = xaccSplitGetValue (split);
if (gnc_numeric_positive_p (target_value) == gnc_numeric_positive_p (split_value))
continue;
// Ok we have found a split that potentially can offset the target value
// Let's see if it's better than what we have found already.
val_cmp = gnc_numeric_compare (gnc_numeric_abs (split_value),
gnc_numeric_abs (target_value));
if (val_cmp == 0)
new_flags += is_equal;
else if (val_cmp > 0)
new_flags += is_more;
else
new_flags += is_less;
if (xaccTransGetTxnType (txn) != TXN_TYPE_LINK)
new_flags += is_pay_split;
if ((new_flags >= best_flags) &&
(gnc_numeric_compare (gnc_numeric_abs (split_value),
gnc_numeric_abs (best_val)) > 0))
{
// The new split is a better match than what we found so far
best_split = split;
best_flags = new_flags;
best_val = split_value;
}
}
return best_split;
}
gboolean
gncOwnerReduceSplitTo (Split *split, gnc_numeric target_value)
{
gnc_numeric split_val = xaccSplitGetValue (split);
gnc_numeric rem_val;
Split *rem_split;
Transaction *txn;
GNCLot *lot;
if (gnc_numeric_positive_p (split_val) != gnc_numeric_positive_p (target_value))
return FALSE; // Split and target value have to be of the same sign
if (gnc_numeric_equal (split_val, target_value))
return FALSE; // Split already has the target value
rem_val = gnc_numeric_sub (split_val, target_value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); // note: values are of opposite sign
rem_split = xaccMallocSplit (xaccSplitGetBook (split));
xaccSplitCopyOnto (split, rem_split);
xaccSplitSetValue (rem_split, rem_val);
txn = xaccSplitGetParent (split);
xaccTransBeginEdit (txn);
xaccSplitSetValue (split, target_value);
xaccSplitSetParent (rem_split, txn);
xaccTransCommitEdit (txn);
lot = xaccSplitGetLot (split);
gnc_lot_add_split (lot, rem_split);
return TRUE;
}
void
gncOwnerSetLotLinkMemo (Transaction *ll_txn)
{
gchar *memo_prefix = _("Offset between documents: ");
gchar *new_memo;
SplitList *lts_iter;
SplitList *splits = NULL, *siter;
GList *titles = NULL, *titer;
if (!ll_txn)
return;
if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
return;
// Find all splits in the lot link transaction that are also in a document lot
for (lts_iter = xaccTransGetSplitList (ll_txn); lts_iter; lts_iter = lts_iter->next)
{
Split *split = lts_iter->data;
GNCLot *lot;
GncInvoice *invoice;
gchar *title;
if (!split)
continue;
lot = xaccSplitGetLot (split);
if (!lot)
continue;
invoice = gncInvoiceGetInvoiceFromLot (lot);
if (!invoice)
continue;
title = g_strdup_printf ("%s %s", gncInvoiceGetTypeString (invoice), gncInvoiceGetID (invoice));
titles = g_list_insert_sorted (titles, title, (GCompareFunc)g_strcmp0);
splits = g_list_prepend (splits, split); // splits don't need to be sorted
}
if (!titles)
return; // We didn't find document lots
// Create the memo as we'd want it to be
new_memo = g_strconcat (memo_prefix, titles->data, NULL);
for (titer = titles->next; titer; titer = titer->next)
{
gchar *tmp_memo = g_strconcat (new_memo, " - ", titer->data, NULL);
g_free (new_memo);
new_memo = tmp_memo;
}
g_list_free_full (titles, g_free);
// Update the memos of all the splits we found previously (if needed)
for (siter = splits; siter; siter = siter->next)
{
if (g_strcmp0 (xaccSplitGetMemo (siter->data), new_memo) != 0)
xaccSplitSetMemo (siter->data, new_memo);
}
g_list_free (splits);
g_free (new_memo);
}
/* Find an existing lot link transaction in the given lot
* Only use a lot link that already links at least two
* documents (to avoid perpetuating the lot link proliferation
* that happened in 2.6.0-2.6.3).
*/
static Transaction *
get_ll_transaction_from_lot (GNCLot *lot)
{
SplitList *ls_iter;
/* This should really only be called on a document lot */
if (!gncInvoiceGetInvoiceFromLot (lot))
return NULL;
/* The given lot is a valid document lot. Now iterate over all
* other lot links in this lot to find one more document lot.
*/
for (ls_iter = gnc_lot_get_split_list (lot); ls_iter; ls_iter = ls_iter->next)
{
Split *ls = ls_iter->data;
Transaction *ll_txn = xaccSplitGetParent (ls);
SplitList *ts_iter;
if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
continue;
for (ts_iter = xaccTransGetSplitList (ll_txn); ts_iter; ts_iter = ts_iter->next)
{
Split *ts = ts_iter->data;
GNCLot *tslot = xaccSplitGetLot (ts);
if (!tslot)
continue;
if (tslot == lot)
continue;
if (gncInvoiceGetInvoiceFromLot (lot))
return ll_txn; /* Got one more document lot - mission accomplished */
}
}
/* The lot doesn't have an ll_txn with the requested criteria... */
return NULL;
}
static void
gncOwnerCreateLotLink (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner)
{
const gchar *action = _("Lot Link");
Account *acct = gnc_lot_get_account (from_lot);
const gchar *name = gncOwnerGetName (gncOwnerGetEndOwner (owner));
Transaction *ll_txn = NULL;
gnc_numeric from_lot_bal, to_lot_bal;
Timespec from_ts, to_ts;
time64 time_posted;
Split *split;
/* Sanity check */
if (!gncInvoiceGetInvoiceFromLot (from_lot) ||
!gncInvoiceGetInvoiceFromLot (to_lot))
return;
/* Determine transaction date based on lot splits */
from_ts = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_latest_split (from_lot)));
to_ts = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_latest_split (to_lot)));
if (timespecToTime64 (from_ts) >= timespecToTime64 (to_ts))
time_posted = timespecToTime64 (from_ts);
else
time_posted = timespecToTime64 (to_ts);
/* Figure out how much we can offset between the lots */
from_lot_bal = gnc_lot_get_balance (from_lot);
to_lot_bal = gnc_lot_get_balance (to_lot);
if (gnc_numeric_compare (gnc_numeric_abs (from_lot_bal),
gnc_numeric_abs (to_lot_bal)) > 0)
from_lot_bal = gnc_numeric_neg (to_lot_bal);
else
to_lot_bal = gnc_numeric_neg (from_lot_bal);
xaccAccountBeginEdit (acct);
/* Look for a pre-existing lot link we can extend */
ll_txn = get_ll_transaction_from_lot (from_lot);
if (!ll_txn)
ll_txn = get_ll_transaction_from_lot (to_lot);
if (!ll_txn)
{
/* No pre-existing lot link. Create one. */
Timespec ts;
timespecFromTime64 (&ts, time_posted);
ll_txn = xaccMallocTransaction (gnc_lot_get_book (from_lot));
xaccTransBeginEdit (ll_txn);
xaccTransSetDescription (ll_txn, name ? name : "(Unknown)");
xaccTransSetCurrency (ll_txn, xaccAccountGetCommodity(acct));
xaccTransSetDateEnteredSecs (ll_txn, gnc_time (NULL));
xaccTransSetDatePostedTS (ll_txn, &ts);
xaccTransSetTxnType (ll_txn, TXN_TYPE_LINK);
}
else
{
Timespec ts = xaccTransRetDatePostedTS (ll_txn);
xaccTransBeginEdit (ll_txn);
/* Maybe we need to update the post date of the transaction ? */
if (time_posted > timespecToTime64 (ts))
{
timespecFromTime64 (&ts, time_posted);
xaccTransSetDatePostedTS (ll_txn, &ts);
}
}
/* Create a split for the from_lot */
split = xaccMallocSplit (gnc_lot_get_book (from_lot));
/* set Action using utility function */
gnc_set_num_action (NULL, split, NULL, action);
xaccAccountInsertSplit (acct, split);
xaccTransAppendSplit (ll_txn, split);
/* To offset the lot balance, the split must be of the opposite sign */
xaccSplitSetBaseValue (split, gnc_numeric_neg (from_lot_bal), xaccAccountGetCommodity(acct));
gnc_lot_add_split (from_lot, split);
/* Create a split for the to_lot */
split = xaccMallocSplit (gnc_lot_get_book (to_lot));
/* set Action using utility function */
gnc_set_num_action (NULL, split, NULL, action);
xaccAccountInsertSplit (acct, split);
xaccTransAppendSplit (ll_txn, split);
/* To offset the lot balance, the split must be of the opposite sign */
xaccSplitSetBaseValue (split, gnc_numeric_neg (to_lot_bal), xaccAccountGetCommodity(acct));
gnc_lot_add_split (to_lot, split);
xaccTransCommitEdit (ll_txn);
/* Do some post-cleaning on the lots
* The above actions may have created splits that are
* in the same transaction and lot. These can be merged.
*/
xaccScrubMergeLotSubSplits (to_lot, FALSE);
xaccScrubMergeLotSubSplits (from_lot, FALSE);
/* And finally set the same memo for all remaining splits
* It's a convenience for the users to identify all documents
* involved in the link.
*/
gncOwnerSetLotLinkMemo (ll_txn);
xaccAccountCommitEdit (acct);
}
static void gncOwnerOffsetLots (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner)
{
gnc_numeric target_offset;
Split *split;
/* from lot should not be a document lot because we're removing a split from there ! */
if (gncInvoiceGetInvoiceFromLot (from_lot))
{
PWARN ("from_lot %p is a document lot. That is not allowed in gncOwnerOffsetLots", from_lot);
return;
}
/* Get best matching split from from_lot to offset to_lot */
target_offset = gnc_lot_get_balance (to_lot);
if (gnc_numeric_zero_p (target_offset))
return; // to_lot is already balanced, nothing more to do
split = gncOwnerFindOffsettingSplit (from_lot, target_offset);
if (!split)
return; // No suitable offsetting split found, nothing more to do
/* If the offsetting split is bigger than the amount needed to balance
* to_lot, reduce the split so its reduced value closes to_lot exactly.
* Note the negation in the reduction function. The split must be of
* opposite sign of to_lot's balance in order to be able to close it.
*/
if (gnc_numeric_compare (gnc_numeric_abs (xaccSplitGetValue (split)),
gnc_numeric_abs (target_offset)) > 0)
gncOwnerReduceSplitTo (split, gnc_numeric_neg (target_offset));
/* Move the reduced split from from_lot to to_lot */
gnc_lot_add_split (to_lot, split);
}
void gncOwnerAutoApplyPaymentsWithLots (const GncOwner *owner, GList *lots)
{
GList *base_iter;
GList *left_iter;
/* General note: in the code below the term "payment" can
* both mean a true payment or a document of
@ -850,165 +1212,127 @@ void gncOwnerAutoApplyPaymentsWithLots (const GncOwner *owner, GList *lots)
if (!owner) return;
if (!lots) return;
for (base_iter = lots; base_iter; base_iter = base_iter->next)
for (left_iter = lots; left_iter; left_iter = left_iter->next)
{
GNCLot *base_lot = base_iter->data;
QofBook *book;
GNCLot *left_lot = left_iter->data;
gnc_numeric left_lot_bal;
gboolean left_lot_has_doc;
gboolean left_modified = FALSE;
Account *acct;
const gchar *name;
GList *lot_list, *lot_iter;
Transaction *txn = NULL;
gnc_numeric base_lot_bal, val_to_pay, val_paid = { 0, 1 };
gboolean base_bal_is_pos;
const gchar *action, *memo;
GList *right_iter;
/* Only attempt to apply payments to open lots.
* Note that due to the iterative nature of this function lots
* in the list may become closed before they are evaluated as
* in the list may become empty/closed before they are evaluated as
* base lot, so we should check this for each lot. */
base_lot_bal = gnc_lot_get_balance (base_lot);
if (gnc_numeric_zero_p (base_lot_bal))
if (!left_lot)
continue;
if (gnc_lot_count_splits (left_lot) == 0)
{
gnc_lot_destroy (left_lot);
left_iter->data = NULL;
continue;
}
if (gnc_lot_is_closed (left_lot))
continue;
book = gnc_lot_get_book (base_lot);
acct = gnc_lot_get_account (base_lot);
name = gncOwnerGetName (gncOwnerGetEndOwner (owner));
lot_list = base_iter->next;
acct = gnc_lot_get_account (left_lot);
xaccAccountBeginEdit (acct);
/* Strings used when creating splits later on. */
action = _("Lot Link");
memo = _("Internal link between invoice and payment lots");
left_lot_bal = gnc_lot_get_balance (left_lot);
left_lot_has_doc = (gncInvoiceGetInvoiceFromLot (left_lot) != NULL);
/* Note: to balance the lot the payment to assign
* must have the opposite sign of the existing lot balance */
val_to_pay = gnc_numeric_neg (base_lot_bal);
base_bal_is_pos = gnc_numeric_positive_p (base_lot_bal);
/* Create splits in a linking transaction between lots until
* - either the invoice lot is balanced
* - or there are no more balancing lots.
/* Attempt to offset left_lot with any of the remaining lots. To do so
* iterate over the remaining lots adding lot links or moving payments
* around.
*/
for (lot_iter = lot_list; lot_iter; lot_iter = lot_iter->next)
for (right_iter = left_iter->next; right_iter; right_iter = right_iter->next)
{
gnc_numeric payment_lot_balance;
Split *split;
Account *bal_acct;
gnc_numeric split_amt;
GNCLot *balancing_lot = lot_iter->data;
GNCLot *right_lot = right_iter->data;
gnc_numeric right_lot_bal;
gboolean right_lot_has_doc;
/* Only attempt to use open lots to balance the base lot.
* Note that due to the iterative nature of this function lots
* in the list may become closed before they are evaluated as
* in the list may become empty/closed before they are evaluated as
* base lot, so we should check this for each lot. */
if (gnc_lot_is_closed (balancing_lot))
if (!right_lot)
continue;
if (gnc_lot_count_splits (right_lot) == 0)
{
gnc_lot_destroy (right_lot);
right_iter->data = NULL;
continue;
}
if (gnc_lot_is_closed (right_lot))
continue;
/* Balancing transactions for invoice/payments can only happen
* in the same account. */
bal_acct = gnc_lot_get_account (balancing_lot);
if (acct != bal_acct)
if (acct != gnc_lot_get_account (right_lot))
continue;
payment_lot_balance = gnc_lot_get_balance (balancing_lot);
/* Only attempt to balance if the base lot and balancing lot are
* of the opposite sign. (Otherwise we would increase the balance
* of the lot - Duh */
if (base_bal_is_pos == gnc_numeric_positive_p (payment_lot_balance))
right_lot_bal = gnc_lot_get_balance (right_lot);
if (gnc_numeric_positive_p (left_lot_bal) == gnc_numeric_positive_p (right_lot_bal))
continue;
/*
* If there is less to pay than there's open in the lot; we're done -- apply the base_lot_vale.
* Note that payment_value and balance are opposite in sign, so we have to compare absolute values here
*
* Otherwise, apply the balance, subtract that from the payment_value,
* and move on to the next one.
/* Ok we found two lots than can (partly) offset each other.
* Depending on the lot types, a different action is needed to accomplish this.
* 1. Both lots are document lots (invoices/credit notes)
* -> Create a lot linking transaction between the lots
* 2. Both lots are payment lots (lots without a document attached)
* -> Use part of the bigger lot to the close the smaller lot
* 3. One document lot with one payment lot
* -> Use (part of) the payment to offset (part of) the document lot,
* Which one will be closed depends on which is the bigger one
*/
if (gnc_numeric_compare (gnc_numeric_abs (val_to_pay), gnc_numeric_abs (payment_lot_balance)) <= 0)
right_lot_has_doc = (gncInvoiceGetInvoiceFromLot (right_lot) != NULL);
if (left_lot_has_doc && right_lot_has_doc)
gncOwnerCreateLotLink (left_lot, right_lot, owner);
else if (!left_lot_has_doc && !right_lot_has_doc)
{
/* abs(val_to_pay) <= abs(balance) */
split_amt = val_to_pay;
gint cmp = gnc_numeric_compare (gnc_numeric_abs (left_lot_bal),
gnc_numeric_abs (right_lot_bal));
if (cmp >= 0)
gncOwnerOffsetLots (left_lot, right_lot, owner);
else
gncOwnerOffsetLots (right_lot, left_lot, owner);
}
else
{
/* abs(val_to_pay) > abs(balance)
* Remember payment_value and balance are opposite in sign,
* and we want a payment to neutralize the current balance
* so we need to negate here */
split_amt = payment_lot_balance;
GNCLot *doc_lot = left_lot_has_doc ? left_lot : right_lot;
GNCLot *pay_lot = left_lot_has_doc ? right_lot : left_lot;
// Ok, let's try to move a payment from pay_lot to doc_lot
gncOwnerOffsetLots (pay_lot, doc_lot, owner);
}
/* If not created yet, create a new transaction linking
* the base lot and the balancing lot(s) */
if (!txn)
/* If we get here, then right_lot was modified
* If the lot has a document, send an event for send an event for it as well
* so it gets potentially updated as paid */
{
Timespec ts = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_latest_split (base_lot)));
xaccAccountBeginEdit (acct);
txn = xaccMallocTransaction (book);
xaccTransBeginEdit (txn);
xaccTransSetDescription (txn, name ? name : "");
xaccTransSetCurrency (txn, xaccAccountGetCommodity(acct));
xaccTransSetDateEnteredSecs (txn, gnc_time (NULL));
xaccTransSetDatePostedTS (txn, &ts);
xaccTransSetTxnType (txn, TXN_TYPE_LINK);
}
/* Create the split for this link in current balancing lot */
split = xaccMallocSplit (book);
xaccSplitSetMemo (split, memo);
/* set Action using utility function */
gnc_set_num_action (NULL, split, NULL, action);
xaccAccountInsertSplit (acct, split);
xaccTransAppendSplit (txn, split);
xaccSplitSetBaseValue (split, gnc_numeric_neg (split_amt), xaccAccountGetCommodity(acct));
gnc_lot_add_split (balancing_lot, split);
/* If the balancing lot was linked to a document (invoice/credit note),
* send an event for it as well so it gets potentially updated as paid */
{
GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(balancing_lot);
GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(right_lot);
if (this_invoice)
qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
}
val_paid = gnc_numeric_add (val_paid, split_amt, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
val_to_pay = gnc_numeric_sub (val_to_pay, split_amt, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
if (gnc_numeric_zero_p (val_to_pay))
break;
left_modified = TRUE;
}
/* If the above loop managed to create a transaction and some balancing splits,
* create the final split for the link transaction in the base lot */
if (txn)
/* If left_lot was modified and the lot has a document,
* send an event for send an event for it as well
* so it gets potentially updated as paid */
if (left_modified)
{
GncInvoice *this_invoice;
Split *split = xaccMallocSplit (book);
xaccSplitSetMemo (split, memo);
/* set Action with utiltity function */
gnc_set_num_action (NULL, split, NULL, action);
xaccAccountInsertSplit (acct, split);
xaccTransAppendSplit (txn, split);
xaccSplitSetBaseValue (split, val_paid, xaccAccountGetCommodity(acct));
gnc_lot_add_split (base_lot, split);
xaccTransCommitEdit (txn);
GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(left_lot);
if (this_invoice)
qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
}
xaccAccountCommitEdit (acct);
/* If the base lot was linked to a document (invoice/credit note),
* send an event for it as well so it gets potentially updated as paid */
this_invoice = gncInvoiceGetInvoiceFromLot(base_lot);
if (this_invoice)
qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
}
}
}

View File

@ -263,6 +263,34 @@ gncOwnerApplyPayment (const GncOwner *owner, Transaction *txn, GList *lots,
gnc_numeric amount, gnc_numeric exch, Timespec date,
const char *memo, const char *num, gboolean auto_pay);
/** Helper function to find a split in lot that best offsets target_value
* Obviously it should be of opposite sign.
* If there are more splits of opposite sign the following
* criteria are used in order of preference:
* 1. exact match in abs value is preferred over larger abs value
* 2. larger abs value is preferred over smaller abs value
* 3. if previous and new candidate are in the same value category,
* prefer real payment splits over lot link splits
* 4. if previous and new candiate are of same split type
* prefer biggest abs value.
*/
Split *gncOwnerFindOffsettingSplit (GNCLot *pay_lot, gnc_numeric target_value);
/** Helper function to reduce the value of a split to target_value. To make
* sure the split's parent transaction remains balanced a second split
* will be created with the remainder. Similarly if the split was part of a
* (business) lot, the remainder split will be added to the same lot to
* keep the lot's balance unchanged.
*/
gboolean gncOwnerReduceSplitTo (Split *split, gnc_numeric target_value);
/** To help a user understand what a lot link transaction does,
* we set the memo to name all documents involved in the link.
* The function below calculates this memo and sets it for
* all splits in the lot link transaction.
*/
void gncOwnerSetLotLinkMemo (Transaction *ll_txn);
/** Returns a GList of account-types based on the owner type */
GList * gncOwnerGetAccountTypesList (const GncOwner *owner);

View File

@ -130,7 +130,6 @@ static void gnc_main_window_destroy (GtkObject *object);
static void gnc_main_window_setup_window (GncMainWindow *window);
static void gnc_window_main_window_init (GncWindowIface *iface);
static gboolean main_window_find_tab_event (GncMainWindow *window, GncPluginPage *page, GtkWidget **event_p);
#ifndef MAC_INTEGRATION
static void gnc_main_window_update_all_menu_items (void);
#endif
@ -2009,31 +2008,11 @@ static void
gnc_main_window_update_tab_color_one_page (GncPluginPage *page,
gpointer user_data)
{
GncMainWindow *window = user_data;
GncMainWindowPrivate *priv;
const gchar *color_string;
GdkColor tab_color;
GtkWidget *event_box;
ENTER("page %p", page);
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
/* Get the event box to update the tab */
main_window_find_tab_event(window, page, &event_box);
color_string = gnc_plugin_page_get_page_color(page);
if (color_string == NULL) color_string = "";
if (gdk_color_parse(color_string, &tab_color) && priv->show_color_tabs)
{
gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, &tab_color);
gtk_widget_modify_bg(event_box, GTK_STATE_ACTIVE, &tab_color);
}
else
{
gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, NULL);
gtk_widget_modify_bg(event_box, GTK_STATE_ACTIVE, NULL);
}
main_window_update_page_color (page, color_string);
LEAVE(" ");
}
@ -2142,7 +2121,7 @@ main_window_find_tab_items (GncMainWindow *window,
GtkWidget **entry_p)
{
GncMainWindowPrivate *priv;
GtkWidget *tab_hbox, *widget, *event_box;
GtkWidget *tab_hbox, *widget, *tab_widget;
GList *children, *tmp;
ENTER("window %p, page %p, label_p %p, entry_p %p",
@ -2156,10 +2135,17 @@ main_window_find_tab_items (GncMainWindow *window,
return FALSE;
}
event_box = gtk_notebook_get_tab_label(GTK_NOTEBOOK(priv->notebook),
tab_widget = gtk_notebook_get_tab_label(GTK_NOTEBOOK(priv->notebook),
page->notebook_page);
tab_hbox = gtk_bin_get_child(GTK_BIN(event_box));
if (GTK_IS_EVENT_BOX (tab_widget))
tab_hbox = gtk_bin_get_child(GTK_BIN(tab_widget));
else if (GTK_IS_HBOX (tab_widget))
tab_hbox = tab_widget;
else
{
PWARN ("Unknown widget for tab label %p", tab_widget);
return FALSE;
}
children = gtk_container_get_children(GTK_CONTAINER(tab_hbox));
for (tmp = children; tmp; tmp = g_list_next(tmp))
@ -2181,16 +2167,15 @@ main_window_find_tab_items (GncMainWindow *window,
}
static gboolean
main_window_find_tab_event (GncMainWindow *window,
main_window_find_tab_widget (GncMainWindow *window,
GncPluginPage *page,
GtkWidget **event_p)
GtkWidget **widget_p)
{
GncMainWindowPrivate *priv;
GtkWidget *event_box;
ENTER("window %p, page %p, event %p",
window, page, event_p);
*event_p = NULL;
ENTER("window %p, page %p, widget %p",
window, page, widget_p);
*widget_p = NULL;
if (!page->notebook_page)
{
@ -2199,17 +2184,11 @@ main_window_find_tab_event (GncMainWindow *window,
}
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
event_box = gtk_notebook_get_tab_label(GTK_NOTEBOOK(priv->notebook),
*widget_p = gtk_notebook_get_tab_label(GTK_NOTEBOOK(priv->notebook),
page->notebook_page);
if (GTK_IS_EVENT_BOX(event_box))
{
*event_p = event_box;
LEAVE("event %p", *event_p);
return (TRUE);
}
LEAVE("event %p", *event_p);
return (FALSE);
LEAVE("widget %p", *widget_p);
return TRUE;
}
void
@ -2218,7 +2197,7 @@ main_window_update_page_name (GncPluginPage *page,
{
GncMainWindow *window;
GncMainWindowPrivate *priv;
GtkWidget *label, *entry, *event_box;
GtkWidget *label, *entry;
gchar *name, *old_page_name, *old_page_long_name;
ENTER(" ");
@ -2264,14 +2243,15 @@ main_window_update_page_name (GncPluginPage *page,
{
gchar *new_page_long_name;
gint string_position;
GtkWidget *tab_widget;
string_position = strlen(old_page_long_name) - strlen(old_page_name);
new_page_long_name = g_strconcat(g_strndup(old_page_long_name, string_position), name, NULL);
gnc_plugin_page_set_page_long_name(page, new_page_long_name);
if (main_window_find_tab_event(window, page, &event_box))
gtk_widget_set_tooltip_text(event_box, new_page_long_name);
if (main_window_find_tab_widget(window, page, &tab_widget))
gtk_widget_set_tooltip_text(tab_widget, new_page_long_name);
g_free(new_page_long_name);
}
@ -2300,44 +2280,55 @@ main_window_update_page_color (GncPluginPage *page,
{
GncMainWindow *window;
GncMainWindowPrivate *priv;
GtkWidget *event_box;
GtkWidget *tab_widget;
GdkColor tab_color;
gchar *color_string;
gchar *color_string = NULL;
gboolean want_color = FALSE;
ENTER(" ");
if ((color_in == NULL) || (*color_in == '\0'))
{
LEAVE("no string");
return;
}
if (color_in)
color_string = g_strstrip(g_strdup(color_in));
/* Optimization, if the color hasn't changed, don't update. */
if (*color_string == '\0' || 0 == g_strcmp0(color_string, gnc_plugin_page_get_page_color(page)))
{
g_free(color_string);
LEAVE("empty string or color unchanged");
return;
}
if (color_string && *color_string != '\0')
want_color = TRUE;
/* Update the plugin */
window = GNC_MAIN_WINDOW(page->window);
if (want_color)
gnc_plugin_page_set_page_color(page, color_string);
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
else
gnc_plugin_page_set_page_color(page, NULL);
/* Update the notebook tab */
main_window_find_tab_event(window, page, &event_box);
main_window_find_tab_widget (window, page, &tab_widget);
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
if (gdk_color_parse(color_string, &tab_color) && priv->show_color_tabs)
if (want_color && gdk_color_parse(color_string, &tab_color) && priv->show_color_tabs)
{
gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, &tab_color);
gtk_widget_modify_bg(event_box, GTK_STATE_ACTIVE, &tab_color);
if (!GTK_IS_EVENT_BOX (tab_widget))
{
GtkWidget *event_box = gtk_event_box_new ();
g_object_ref (tab_widget);
gtk_notebook_set_tab_label (GTK_NOTEBOOK(priv->notebook),
page->notebook_page, event_box);
gtk_container_add (GTK_CONTAINER(event_box), tab_widget);
g_object_unref (tab_widget);
tab_widget = event_box;
}
gtk_widget_modify_bg(tab_widget, GTK_STATE_NORMAL, &tab_color);
gtk_widget_modify_bg(tab_widget, GTK_STATE_ACTIVE, &tab_color);
}
else
{
gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, NULL);
gtk_widget_modify_bg(event_box, GTK_STATE_ACTIVE, NULL);
if (GTK_IS_EVENT_BOX (tab_widget))
{
GtkWidget *tab_hbox = gtk_bin_get_child(GTK_BIN(tab_widget));
g_object_ref (tab_hbox);
gtk_container_remove (GTK_CONTAINER(tab_widget), tab_hbox);
gtk_notebook_set_tab_label (GTK_NOTEBOOK(priv->notebook),
page->notebook_page, tab_hbox);
g_object_unref (tab_hbox);
}
}
g_free(color_string);
LEAVE("done");
@ -2882,7 +2873,7 @@ gnc_main_window_open_page (GncMainWindow *window,
{
GncMainWindowPrivate *priv;
GtkWidget *tab_hbox;
GtkWidget *label, *entry, *event_box;
GtkWidget *label, *entry;
const gchar *icon, *text, *color_string;
GtkWidget *image;
GList *tmp;
@ -2955,27 +2946,10 @@ gnc_main_window_open_page (GncMainWindow *window,
else
gtk_box_pack_start (GTK_BOX (tab_hbox), label, TRUE, TRUE, 0);
event_box = gtk_event_box_new();
gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box), TRUE);
gtk_widget_show(event_box);
gtk_container_add(GTK_CONTAINER(event_box), tab_hbox);
color_string = gnc_plugin_page_get_page_color(page);
if (color_string == NULL) color_string = "";
if (gdk_color_parse(color_string, &tab_color) && priv->show_color_tabs)
{
gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, &tab_color);
gtk_widget_modify_bg(event_box, GTK_STATE_ACTIVE, &tab_color);
}
else
{
gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, NULL);
gtk_widget_modify_bg(event_box, GTK_STATE_ACTIVE, NULL);
}
text = gnc_plugin_page_get_page_long_name(page);
if (text)
{
gtk_widget_set_tooltip_text(event_box, text);
gtk_widget_set_tooltip_text(tab_hbox, text);
}
entry = gtk_entry_new();
@ -3029,7 +3003,10 @@ gnc_main_window_open_page (GncMainWindow *window,
/*
* Now install it all in the window.
*/
gnc_main_window_connect(window, page, event_box, label);
gnc_main_window_connect(window, page, tab_hbox, label);
color_string = gnc_plugin_page_get_page_color(page);
main_window_update_page_color (page, color_string);
LEAVE("");
}

View File

@ -868,6 +868,7 @@ gnc_plugin_page_set_page_color (GncPluginPage *page, const gchar *color)
priv = GNC_PLUGIN_PAGE_GET_PRIVATE(page);
if (priv->page_color)
g_free(priv->page_color);
if (color)
priv->page_color = g_strdup(color);
}

View File

@ -259,7 +259,7 @@ gnc_tree_view_add_date_column (GncTreeView *view,
* column used to determine the foreground color of any text in this
* column. It should be used to display negative numbers in red.
* Use GNC_TREE_VIEW_COLUMN_COLOR_NONE if the text in this column
* should always be displayed in black.
* should always be displayed in the default theme color for text.
*
* @param model_visibility_column The index of the GtkTreeModel data
* column used to determine whether or not a checkbox for each row

View File

@ -40,7 +40,6 @@
#include "Recurrence.h"
#include "Query.h"
#include "Scrub.h"
#include "Scrub3.h"
#include "Transaction.h"
#include "dialog-utils.h"
#include "assistant-acct-period.h"

View File

@ -38,6 +38,7 @@
#include "qof.h"
#include "gnc-lot.h"
#include "Scrub3.h"
#include "ScrubBusiness.h"
#include "Transaction.h"
#include "engine-helpers.h"
#include "gncInvoice.h"
@ -750,6 +751,9 @@ lv_response_cb (GtkDialog *dialog, gint response, gpointer data)
case RESPONSE_SCRUB_LOT:
if (NULL == lot)
return;
if (xaccAccountIsAPARType (xaccAccountGetType(lv->account)))
gncScrubBusinessLot (lot);
else
xaccScrubLot (lot);
gnc_lot_viewer_fill (lv);
lv_show_splits_in_lot (lv);
@ -757,6 +761,9 @@ lv_response_cb (GtkDialog *dialog, gint response, gpointer data)
case RESPONSE_SCRUB_ACCOUNT:
gnc_suspend_gui_refresh ();
if (xaccAccountIsAPARType (xaccAccountGetType(lv->account)))
gncScrubBusinessAccountLots (lv->account);
else
xaccAccountScrubLots (lv->account);
gnc_resume_gui_refresh ();
gnc_lot_viewer_fill (lv);

View File

@ -42,6 +42,7 @@
#include "Scrub.h"
#include "Scrub3.h"
#include "ScrubBusiness.h"
#include "Transaction.h"
#include "dialog-account.h"
#include "dialog-transfer.h"
@ -1568,10 +1569,13 @@ gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountT
xaccAccountScrubOrphans (account);
xaccAccountScrubImbalance (account);
// XXX: Lots are disabled
// XXX: Lots/capital gains scrubbing is disabled
if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
xaccAccountScrubLots(account);
gncScrubBusinessAccountLots(account);
gnc_resume_gui_refresh ();
}
@ -1587,10 +1591,12 @@ gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAcco
xaccAccountTreeScrubOrphans (account);
xaccAccountTreeScrubImbalance (account);
// XXX: Lots are disabled
// XXX: Lots/capital gains scrubbing is disabled
if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
xaccAccountTreeScrubLots(account);
gncScrubBusinessAccountTreeLots(account);
gnc_resume_gui_refresh ();
}
@ -1603,10 +1609,12 @@ gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAcco
xaccAccountTreeScrubOrphans (root);
xaccAccountTreeScrubImbalance (root);
// XXX: Lots are disabled
// XXX: Lots/capital gains scrubbing is disabled
if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
xaccAccountTreeScrubLots(root);
gncScrubBusinessAccountTreeLots(root);
gnc_resume_gui_refresh ();
}

View File

@ -74,6 +74,7 @@
#include "gnucash-sheet.h"
#include "dialog-lot-viewer.h"
#include "Scrub.h"
#include "ScrubBusiness.h"
#include "qof.h"
#include "window-reconcile.h"
#include "window-autoclear.h"
@ -3691,6 +3692,8 @@ gnc_plugin_page_register_cmd_scrub_current (GtkAction *action,
Query *query;
Account *root;
Transaction *trans;
Split *split;
GNCLot *lot;
SplitRegister *reg;
g_return_if_fail(GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page));
@ -3717,6 +3720,11 @@ gnc_plugin_page_register_cmd_scrub_current (GtkAction *action,
root = gnc_get_current_root_account();
xaccTransScrubOrphans(trans);
xaccTransScrubImbalance(trans, root, NULL);
split = gnc_split_register_get_current_split (reg);
lot = xaccSplitGetLot (split);
if (lot && xaccAccountIsAPARType (xaccAccountGetType (xaccSplitGetAccount (split))))
gncScrubBusinessLot (lot);
gnc_resume_gui_refresh();
LEAVE(" ");
}
@ -3729,6 +3737,7 @@ gnc_plugin_page_register_cmd_scrub_all (GtkAction *action,
Query *query;
Account *root;
Transaction *trans;
GNCLot *lot;
Split *split;
GList *node;
@ -3754,6 +3763,10 @@ gnc_plugin_page_register_cmd_scrub_all (GtkAction *action,
xaccTransScrubOrphans(trans);
xaccTransScrubImbalance(trans, root, NULL);
lot = xaccSplitGetLot (split);
if (lot && xaccAccountIsAPARType (xaccAccountGetType (xaccSplitGetAccount (split))))
gncScrubBusinessLot (lot);
}
gnc_resume_gui_refresh();

View File

@ -26,7 +26,6 @@
#include <glib/gi18n.h>
#include "Scrub.h"
#include "Scrub3.h"
#include "dialog-account.h"
#include "dialog-transfer.h"
#include "dialog-utils.h"

View File

@ -39,18 +39,6 @@
#include "split-register-p.h"
#include "engine-helpers.h"
static SplitRegisterColors reg_colors =
{
0x96B183,
0xBFDEB9,
0xF6FFDA,
0xFFEF98,
0xFFEF98,
0xEDE7D3,
0xFFEF98,
};
/* This static indicates the debugging module that this .o belongs to. */
static QofLogModule log_module = GNC_MOD_LEDGER;
@ -513,84 +501,164 @@ get_trans_total_balance (SplitRegister *reg, Transaction *trans)
}
static guint32
gnc_split_register_get_shares_fg_color (VirtualLocation virt_loc,
gpointer user_data)
gnc_split_register_get_color_internal (VirtualLocation virt_loc,
SplitRegister *reg,
const guint32 *color_table,
gboolean foreground)
{
SplitRegister *reg = user_data;
const guint32 black = 0x000000;
const guint32 red = 0xff0000;
const char * cell_name;
const char *cursor_name;
VirtualCell *vcell;
gboolean is_current;
gnc_numeric shares;
Split *split;
gboolean double_alternate_virt;
guint32 colorbase = 0; /* By default return background colors */
if (!use_red_for_negative)
return black;
if (foreground)
colorbase = COLOR_UNKNOWN_FG; /* a bit of enum arithmetic */
split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
if (!split)
return black;
if (!reg)
return color_table[colorbase + COLOR_UNKNOWN_BG];
cell_name = gnc_table_get_cell_name (reg->table, virt_loc);
if (gnc_table_virtual_location_in_header (reg->table, virt_loc))
return color_table[colorbase + COLOR_HEADER_BG];
vcell = gnc_table_get_virtual_cell (reg->table, virt_loc.vcell_loc);
if (!vcell || !vcell->cellblock)
return color_table[colorbase + COLOR_UNKNOWN_BG];
if ((virt_loc.phys_col_offset < vcell->cellblock->start_col) ||
(virt_loc.phys_col_offset > vcell->cellblock->stop_col))
return color_table[colorbase + COLOR_UNKNOWN_BG];
is_current = virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
virt_loc.vcell_loc);
if (gnc_cell_name_equal (cell_name, TSHRS_CELL))
shares = get_trans_total_amount (reg, xaccSplitGetParent (split));
else if (is_current)
shares = gnc_price_cell_get_value
((PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
SHRS_CELL));
else
shares = xaccSplitGetAmount (split);
cursor_name = vcell->cellblock->cursor_name;
if (gnc_numeric_negative_p (shares))
return red;
if (g_strcmp0 (cursor_name, CURSOR_SINGLE_JOURNAL) == 0 ||
g_strcmp0 (cursor_name, CURSOR_SINGLE_LEDGER) == 0)
{
if (is_current)
return vcell->start_primary_color ?
color_table[colorbase + COLOR_PRIMARY_BG_ACTIVE] :
color_table[colorbase + COLOR_SECONDARY_BG_ACTIVE];
return black;
return vcell->start_primary_color ?
color_table[colorbase + COLOR_PRIMARY_BG] : color_table[colorbase + COLOR_SECONDARY_BG];
}
if (g_strcmp0 (cursor_name, CURSOR_DOUBLE_JOURNAL) == 0 ||
g_strcmp0 (cursor_name, CURSOR_DOUBLE_JOURNAL_NUM_ACTN) == 0 ||
g_strcmp0 (cursor_name, CURSOR_DOUBLE_LEDGER) == 0 ||
g_strcmp0 (cursor_name, CURSOR_DOUBLE_LEDGER_NUM_ACTN) == 0)
{
double_alternate_virt = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
GNC_PREF_ALT_COLOR_BY_TRANS);
if (is_current)
{
if (double_alternate_virt)
return vcell->start_primary_color ?
color_table[colorbase + COLOR_PRIMARY_BG_ACTIVE] :
color_table[colorbase + COLOR_SECONDARY_BG_ACTIVE];
return (virt_loc.phys_row_offset % 2 == 0) ?
color_table[colorbase + COLOR_PRIMARY_BG_ACTIVE] :
color_table[colorbase + COLOR_SECONDARY_BG_ACTIVE];
}
if (double_alternate_virt)
return vcell->start_primary_color ?
color_table[colorbase + COLOR_PRIMARY_BG] :
color_table[colorbase + COLOR_SECONDARY_BG];
return (virt_loc.phys_row_offset % 2 == 0) ?
color_table[colorbase + COLOR_PRIMARY_BG] :
color_table[colorbase + COLOR_SECONDARY_BG];
}
if (g_strcmp0 (cursor_name, CURSOR_SPLIT) == 0)
{
if (is_current)
return color_table[colorbase + COLOR_SPLIT_BG_ACTIVE];
return color_table[colorbase + COLOR_SPLIT_BG];
}
PWARN ("Unexpected cursor: %s\n", cursor_name);
return color_table[colorbase + COLOR_UNKNOWN_BG];
}
static guint32
gnc_split_register_get_balance_fg_color (VirtualLocation virt_loc,
gpointer user_data)
gnc_split_register_get_fg_color_internal (VirtualLocation virt_loc,
SplitRegister *reg,
const guint32 *color_table)
{
SplitRegister *reg = user_data;
const guint32 black = 0x000000;
const guint32 red = 0xff0000;
const guint32 red_color = color_table[COLOR_NEGATIVE];
guint32 fg_color;
const char * cell_name;
gnc_numeric balance;
gboolean is_current;
gnc_numeric value;
Split *split;
fg_color = gnc_split_register_get_color_internal (virt_loc, reg, color_table, TRUE);
if (!use_red_for_negative)
return black;
return fg_color;
split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
if (!split)
return black;
return fg_color;
cell_name = gnc_table_get_cell_name (reg->table, virt_loc);
if (gnc_cell_name_equal (cell_name, BALN_CELL))
balance = xaccSplitGetBalance (split);
else if (gnc_cell_name_equal (cell_name, RBALN_CELL))
balance = gnc_split_register_get_rbaln (virt_loc, user_data, TRUE);
else
balance = get_trans_total_balance (reg, xaccSplitGetParent (split));
if (gnc_cell_name_equal (cell_name, TSHRS_CELL))
value = get_trans_total_amount (reg, xaccSplitGetParent (split));
else if (gnc_cell_name_equal (cell_name, SHRS_CELL))
{
Account *account;
account = xaccSplitGetAccount (split);
if (virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
virt_loc.vcell_loc))
value = gnc_price_cell_get_value
((PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
SHRS_CELL));
else
value = xaccSplitGetAmount (split);
}
else if (gnc_cell_name_equal (cell_name, BALN_CELL))
value = xaccSplitGetBalance (split);
else if (gnc_cell_name_equal (cell_name, RBALN_CELL))
value = gnc_split_register_get_rbaln (virt_loc, reg, TRUE);
else if (gnc_cell_name_equal (cell_name, TBALN_CELL))
value = get_trans_total_balance (reg, xaccSplitGetParent (split));
if ((gnc_cell_name_equal (cell_name, BALN_CELL)) ||
(gnc_cell_name_equal (cell_name, RBALN_CELL)) ||
(gnc_cell_name_equal (cell_name, TBALN_CELL)))
{
Account *account = xaccSplitGetAccount (split);
if (gnc_reverse_balance (account))
balance = gnc_numeric_neg (balance);
value = gnc_numeric_neg (value);
}
if (gnc_numeric_negative_p (balance))
return red;
if (gnc_numeric_negative_p (value))
return red_color;
return black;
return fg_color;
}
static guint32
gnc_split_register_get_fg_color (VirtualLocation virt_loc,
gpointer user_data)
{
SplitRegister *reg = user_data;
return gnc_split_register_get_fg_color_internal (virt_loc, reg, reg_colors_default);
}
static guint32
gnc_split_register_get_gtkrc_fg_color (VirtualLocation virt_loc,
gpointer user_data)
{
SplitRegister *reg = user_data;
return gnc_split_register_get_fg_color_internal (virt_loc, reg, reg_colors_gtkrc);
}
static guint32
@ -599,89 +667,13 @@ gnc_split_register_get_bg_color (VirtualLocation virt_loc,
gpointer user_data)
{
SplitRegister *reg = user_data;
const char *cursor_name;
VirtualCell *vcell;
guint32 bg_color;
gboolean is_current;
gboolean double_alternate_virt;
if (hatching)
*hatching = FALSE;
bg_color = 0xffffff; /* white */
if (!reg)
return bg_color;
if (gnc_table_virtual_location_in_header (reg->table, virt_loc))
return reg_colors.header_bg_color;
vcell = gnc_table_get_virtual_cell (reg->table, virt_loc.vcell_loc);
if (!vcell || !vcell->cellblock)
return bg_color;
if ((virt_loc.phys_col_offset < vcell->cellblock->start_col) ||
(virt_loc.phys_col_offset > vcell->cellblock->stop_col))
return bg_color;
is_current = virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
virt_loc.vcell_loc);
cursor_name = vcell->cellblock->cursor_name;
if (g_strcmp0 (cursor_name, CURSOR_SINGLE_JOURNAL) == 0 ||
g_strcmp0 (cursor_name, CURSOR_SINGLE_LEDGER) == 0)
{
if (is_current)
return vcell->start_primary_color ?
reg_colors.primary_active_bg_color :
reg_colors.secondary_active_bg_color;
return vcell->start_primary_color ?
reg_colors.primary_bg_color : reg_colors.secondary_bg_color;
return gnc_split_register_get_color_internal (virt_loc, reg, reg_colors_default, FALSE);
}
if (g_strcmp0 (cursor_name, CURSOR_DOUBLE_JOURNAL) == 0 ||
g_strcmp0 (cursor_name, CURSOR_DOUBLE_JOURNAL_NUM_ACTN) == 0 ||
g_strcmp0 (cursor_name, CURSOR_DOUBLE_LEDGER) == 0 ||
g_strcmp0 (cursor_name, CURSOR_DOUBLE_LEDGER_NUM_ACTN) == 0)
{
double_alternate_virt = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
GNC_PREF_ALT_COLOR_BY_TRANS);
if (is_current)
{
if (double_alternate_virt)
return vcell->start_primary_color ?
reg_colors.primary_active_bg_color :
reg_colors.secondary_active_bg_color;
return (virt_loc.phys_row_offset % 2 == 0) ?
reg_colors.primary_active_bg_color :
reg_colors.secondary_active_bg_color;
}
if (double_alternate_virt)
return vcell->start_primary_color ?
reg_colors.primary_bg_color :
reg_colors.secondary_bg_color;
return (virt_loc.phys_row_offset % 2 == 0) ?
reg_colors.primary_bg_color :
reg_colors.secondary_bg_color;
}
if (g_strcmp0 (cursor_name, CURSOR_SPLIT) == 0)
{
if (is_current)
return reg_colors.split_active_bg_color;
return reg_colors.split_bg_color;
}
PWARN ("Unexpected cursor: %s\n", cursor_name);
return bg_color;
}
static RegisterColor
gnc_split_register_get_gtkrc_bg_color (VirtualLocation virt_loc,
@ -689,82 +681,11 @@ gnc_split_register_get_gtkrc_bg_color (VirtualLocation virt_loc,
gpointer user_data)
{
SplitRegister *reg = user_data;
const char *cursor_name;
VirtualCell *vcell;
gboolean is_current;
gboolean double_alternate_virt;
if (!reg)
return COLOR_UNKNOWN;
if (hatching)
*hatching = FALSE;
if (gnc_table_virtual_location_in_header (reg->table, virt_loc))
return COLOR_HEADER;
vcell = gnc_table_get_virtual_cell (reg->table, virt_loc.vcell_loc);
if (!vcell || !vcell->cellblock)
return COLOR_UNKNOWN;
if ((virt_loc.phys_col_offset < vcell->cellblock->start_col) ||
(virt_loc.phys_col_offset > vcell->cellblock->stop_col))
return COLOR_UNKNOWN;
is_current = virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
virt_loc.vcell_loc);
cursor_name = vcell->cellblock->cursor_name;
if (g_strcmp0 (cursor_name, CURSOR_SINGLE_JOURNAL) == 0 ||
g_strcmp0 (cursor_name, CURSOR_SINGLE_LEDGER) == 0)
{
if (is_current)
return vcell->start_primary_color ?
COLOR_PRIMARY_ACTIVE :
COLOR_SECONDARY_ACTIVE;
return vcell->start_primary_color ?
COLOR_PRIMARY : COLOR_SECONDARY;
}
if (g_strcmp0 (cursor_name, CURSOR_DOUBLE_JOURNAL) == 0 ||
g_strcmp0 (cursor_name, CURSOR_DOUBLE_JOURNAL_NUM_ACTN) == 0 ||
g_strcmp0 (cursor_name, CURSOR_DOUBLE_LEDGER) == 0 ||
g_strcmp0 (cursor_name, CURSOR_DOUBLE_LEDGER_NUM_ACTN) == 0)
{
double_alternate_virt = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
GNC_PREF_ALT_COLOR_BY_TRANS);
if (is_current)
{
if (double_alternate_virt)
return vcell->start_primary_color ?
COLOR_PRIMARY_ACTIVE :
COLOR_SECONDARY_ACTIVE;
return (virt_loc.phys_row_offset % 2 == 0) ?
COLOR_PRIMARY_ACTIVE :
COLOR_SECONDARY_ACTIVE;
}
if (double_alternate_virt)
return vcell->start_primary_color ?
COLOR_PRIMARY :
COLOR_SECONDARY;
return (virt_loc.phys_row_offset % 2 == 0) ?
COLOR_PRIMARY :
COLOR_SECONDARY;
}
if (g_strcmp0 (cursor_name, CURSOR_SPLIT) == 0)
{
if (is_current)
return COLOR_SPLIT_ACTIVE;
return COLOR_SPLIT;
}
PWARN ("Unexpected cursor: %s\n", cursor_name);
return COLOR_UNKNOWN;
return gnc_split_register_get_color_internal (virt_loc, reg, reg_colors_gtkrc, FALSE);
}
static guint32
@ -2662,19 +2583,22 @@ gnc_split_register_model_new (void)
gnc_table_model_set_fg_color_handler(
model, gnc_split_register_get_shares_fg_color, SHRS_CELL);
model, gnc_split_register_get_fg_color, SHRS_CELL);
gnc_table_model_set_fg_color_handler(
model, gnc_split_register_get_shares_fg_color, TSHRS_CELL);
model, gnc_split_register_get_fg_color, TSHRS_CELL);
gnc_table_model_set_fg_color_handler(
model, gnc_split_register_get_balance_fg_color, BALN_CELL);
model, gnc_split_register_get_fg_color, BALN_CELL);
gnc_table_model_set_fg_color_handler(
model, gnc_split_register_get_balance_fg_color, TBALN_CELL);
model, gnc_split_register_get_fg_color, TBALN_CELL);
gnc_table_model_set_fg_color_handler(
model, gnc_split_register_get_balance_fg_color, RBALN_CELL);
model, gnc_split_register_get_fg_color, RBALN_CELL);
gnc_table_model_set_fg_color_handler(
model, gnc_split_register_get_gtkrc_fg_color, "gtkrc");
gnc_table_model_set_default_bg_color_handler(

View File

@ -28,16 +28,4 @@
TableModel * gnc_split_register_model_new (void);
TableModel * gnc_template_register_model_new (void);
typedef enum
{
COLOR_UNKNOWN,
COLOR_HEADER,
COLOR_PRIMARY,
COLOR_PRIMARY_ACTIVE,
COLOR_SECONDARY,
COLOR_SECONDARY_ACTIVE,
COLOR_SPLIT,
COLOR_SPLIT_ACTIVE,
} RegisterColor;
#endif

View File

@ -238,20 +238,6 @@ typedef enum
NUM_CURSOR_CLASSES
} CursorClass;
typedef struct split_register_colors
{
guint32 header_bg_color;
guint32 primary_bg_color;
guint32 secondary_bg_color;
guint32 primary_active_bg_color;
guint32 secondary_active_bg_color;
guint32 split_bg_color;
guint32 split_active_bg_color;
} SplitRegisterColors;
/** @brief A split register created with ::gnc_split_register_new */
typedef struct split_register SplitRegister;
@ -270,7 +256,7 @@ struct split_register
or split action for number
field in register */
gboolean is_template;
gboolean do_auto_complete; /**< whether to use auto-competion */
gboolean do_auto_complete; /**< whether to use auto-completion */
SRInfo * sr_info; /**< private data; outsiders should not access this */
};

View File

@ -345,19 +345,21 @@ gnc_table_get_label (Table *table, VirtualLocation virt_loc)
return label;
}
guint32
gnc_table_get_fg_color (Table *table, VirtualLocation virt_loc)
static guint32
gnc_table_get_fg_color_internal (Table *table, VirtualLocation virt_loc,
gboolean want_gtkrc)
{
TableGetFGColorHandler fg_color_handler;
const char *cell_name;
const char *handler_name = "gtkrc";
if (!table || !table->model)
return 0x0; /* black */
cell_name = gnc_table_get_cell_name (table, virt_loc);
if (!want_gtkrc)
handler_name = gnc_table_get_cell_name (table, virt_loc);
fg_color_handler = gnc_table_model_get_fg_color_handler (table->model,
cell_name);
handler_name);
if (!fg_color_handler)
return 0x0;
@ -365,11 +367,24 @@ gnc_table_get_fg_color (Table *table, VirtualLocation virt_loc)
}
guint32
gnc_table_get_bg_color (Table *table, VirtualLocation virt_loc,
gboolean *hatching)
gnc_table_get_fg_color (Table *table, VirtualLocation virt_loc)
{
return gnc_table_get_fg_color_internal (table, virt_loc, FALSE);
}
guint32
gnc_table_get_gtkrc_fg_color (Table *table, VirtualLocation virt_loc)
{
return gnc_table_get_fg_color_internal (table, virt_loc, TRUE);
}
static guint32
gnc_table_get_bg_color_internal (Table *table, VirtualLocation virt_loc,
gboolean *hatching,
gboolean want_gtkrc)
{
TableGetBGColorHandler bg_color_handler;
const char *cell_name;
const char *handler_name = "gtkrc";
if (hatching)
*hatching = FALSE;
@ -377,10 +392,11 @@ gnc_table_get_bg_color (Table *table, VirtualLocation virt_loc,
if (!table || !table->model)
return 0xffffff; /* white */
cell_name = gnc_table_get_cell_name (table, virt_loc);
if (!want_gtkrc)
handler_name = gnc_table_get_cell_name (table, virt_loc);
bg_color_handler = gnc_table_model_get_bg_color_handler (table->model,
cell_name);
handler_name);
if (!bg_color_handler)
return 0xffffff;
@ -388,25 +404,18 @@ gnc_table_get_bg_color (Table *table, VirtualLocation virt_loc,
table->model->handler_user_data);
}
guint32
gnc_table_get_bg_color (Table *table, VirtualLocation virt_loc,
gboolean *hatching)
{
return gnc_table_get_bg_color_internal (table, virt_loc, hatching, FALSE);
}
guint32
gnc_table_get_gtkrc_bg_color (Table *table, VirtualLocation virt_loc,
gboolean *hatching)
{
TableGetBGColorHandler bg_color_handler;
if (hatching)
*hatching = FALSE;
if (!table || !table->model)
return 0xffffff; /* white */
bg_color_handler = gnc_table_model_get_bg_color_handler (table->model,
"gtkrc");
if (!bg_color_handler)
return 0xffffff;
return bg_color_handler (virt_loc, hatching,
table->model->handler_user_data);
return gnc_table_get_bg_color_internal (table, virt_loc, hatching, TRUE);
}
void

View File

@ -156,6 +156,92 @@ struct table
gpointer ui_data;
};
/** Color definitions used for table elements */
typedef enum
{
/* Colors used for background drawing */
COLOR_UNKNOWN_BG,
COLOR_HEADER_BG,
COLOR_PRIMARY_BG,
COLOR_PRIMARY_BG_ACTIVE,
COLOR_SECONDARY_BG,
COLOR_SECONDARY_BG_ACTIVE,
COLOR_SPLIT_BG,
COLOR_SPLIT_BG_ACTIVE,
/* Colors used for foreground drawing (text etc)
* ATTENTION: the background and foreground lists should have
* the same types (the same amount of entries) !
* The code relies on this ! */
COLOR_UNKNOWN_FG,
COLOR_HEADER_FG,
COLOR_PRIMARY_FG,
COLOR_PRIMARY_FG_ACTIVE,
COLOR_SECONDARY_FG,
COLOR_SECONDARY_FG_ACTIVE,
COLOR_SPLIT_FG,
COLOR_SPLIT_FG_ACTIVE,
/* Other colors */
COLOR_NEGATIVE, /* Color to use for negative numbers */
} RegisterColor;
/* Alternative color tables to use for the register.
* The colors in this array are ordered according to the RegisterColor Enum
* Be careful to respect this order !
*/
static const guint32 reg_colors_default [] =
{
0xFFFFFF, // COLOR_UNKNOWN_BG
0x96B183, // COLOR_HEADER_BG
0xBFDEB9, // COLOR_PRIMARY_BG
0xFFEF98, // COLOR_PRIMARY_BG_ACTIVE
0xF6FFDA, // COLOR_SECONDARY_BG
0xFFEF98, // COLOR_SECONDARY_BG_ACTIVE
0xEDE7D3, // COLOR_SPLIT_BG
0xFFEF98, // COLOR_SPLIT_BG_ACTIVE
0x000000, // COLOR_UNKNOWN_FG
0x000000, // COLOR_HEADER_FG
0x000000, // COLOR_PRIMARY_FG
0x000000, // COLOR_PRIMARY_FG_ACTIVE
0x000000, // COLOR_SECONDARY_FG
0x000000, // COLOR_SECONDARY_FG_ACTIVE
0x000000, // COLOR_SPLIT_FG
0x000000, // COLOR_SPLIT_FG_ACTIVE
0xFF0000, // COLOR_NEGATIVE
};
/* The colors in this array are ordered according to the RegisterColor Enum
* Be careful to respect this order !
*/
static const guint32 reg_colors_gtkrc [] =
{
COLOR_UNKNOWN_BG, // COLOR_UNKNOWN_BG
COLOR_HEADER_BG, // COLOR_HEADER_BG
COLOR_PRIMARY_BG, // COLOR_PRIMARY_BG
COLOR_PRIMARY_BG_ACTIVE, // COLOR_PRIMARY_BG_ACTIVE
COLOR_SECONDARY_BG, // COLOR_SECONDARY_BG
COLOR_SECONDARY_BG_ACTIVE, // COLOR_SECONDARY_BG_ACTIVE
COLOR_SPLIT_BG, // COLOR_SPLIT_BG
COLOR_SPLIT_BG_ACTIVE, // COLOR_SPLIT_BG_ACTIVE
COLOR_UNKNOWN_FG, // COLOR_UNKNOWN_FG
COLOR_HEADER_FG, // COLOR_HEADER_FG
COLOR_PRIMARY_FG, // COLOR_PRIMARY_FG
COLOR_PRIMARY_FG_ACTIVE, // COLOR_PRIMARY_FG_ACTIVE
COLOR_SECONDARY_FG, // COLOR_SECONDARY_FG
COLOR_SECONDARY_FG_ACTIVE, // COLOR_SECONDARY_FG_ACTIVE
COLOR_SPLIT_FG, // COLOR_SPLIT_FG
COLOR_SPLIT_FG_ACTIVE, // COLOR_SPLIT_FG_ACTIVE
COLOR_NEGATIVE, // COLOR_NEGATIVE
};
/* Set the default gui handlers used by new tables. */
void gnc_table_set_default_gui_handlers (TableGUIHandlers *gui_handlers);
@ -210,6 +296,8 @@ CellIOFlags gnc_table_get_io_flags (Table *table, VirtualLocation virt_loc);
guint32 gnc_table_get_fg_color (Table *table, VirtualLocation virt_loc);
guint32 gnc_table_get_gtkrc_fg_color (Table *table, VirtualLocation virt_loc);
guint32 gnc_table_get_bg_color (Table *table, VirtualLocation virt_loc,
gboolean *hatching);
guint32 gnc_table_get_gtkrc_bg_color (Table *table, VirtualLocation virt_loc,

View File

@ -605,6 +605,13 @@ draw_cell (GnucashGrid *grid,
context = pango_layout_get_context (layout);
font = pango_font_description_copy (pango_context_get_font_description (context));
if (grid->sheet->use_theme_colors)
{
color_type = gnc_table_get_gtkrc_fg_color (table, virt_loc);
fg_color = get_gtkrc_color(grid->sheet, color_type);
}
else
{
argb = gnc_table_get_fg_color (table, virt_loc);
#ifdef READONLY_LINES_WITH_CHANGED_FG_COLOR
// Are we in a read-only row? Then make the foreground color somewhat less black
@ -616,6 +623,7 @@ draw_cell (GnucashGrid *grid,
}
#endif
fg_color = gnucash_color_argb_to_gdk (argb);
}
gdk_gc_set_foreground (grid->gc, fg_color);

View File

@ -75,7 +75,7 @@ gnc_header_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
VirtualLocation virt_loc;
VirtualCell *vcell;
CellDimensions *cd;
GdkColor *bg_color;
GdkColor *bg_color, *fg_color;
int xpaint, ypaint;
const char *text;
CellBlock *cb;
@ -94,11 +94,15 @@ gnc_header_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
color_type = gnc_table_get_gtkrc_bg_color (table, virt_loc,
NULL);
bg_color = get_gtkrc_color(header->sheet, color_type);
color_type = gnc_table_get_gtkrc_fg_color (table, virt_loc);
fg_color = get_gtkrc_color(header->sheet, color_type);
}
else
{
argb = gnc_table_get_bg_color (table, virt_loc, NULL);
bg_color = gnucash_color_argb_to_gdk (argb);
argb = gnc_table_get_fg_color (table, virt_loc);
fg_color = gnucash_color_argb_to_gdk (argb);
}
h = style->dimensions->height;
@ -111,7 +115,7 @@ gnc_header_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
style->dimensions->width, h);
gdk_gc_set_line_attributes (header->gc, 1, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
gdk_gc_set_foreground (header->gc, &gn_black);
gdk_gc_set_foreground (header->gc, fg_color);
gdk_draw_rectangle (drawable, header->gc, FALSE, -x, -y,
style->dimensions->width, h);
@ -121,7 +125,7 @@ gnc_header_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
gdk_gc_set_line_attributes (header->gc, 1, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
gdk_gc_set_background (header->gc, &gn_white);
gdk_gc_set_foreground (header->gc, &gn_black);
gdk_gc_set_foreground (header->gc, fg_color);
/*font = gnucash_register_font;*/
vcell = gnc_table_get_virtual_cell

View File

@ -196,16 +196,20 @@ gnc_item_edit_draw_info (GncItemEdit *item_edit, int x, int y, TextDrawInfo *inf
item_edit->virt_loc,
&hatching);
info->bg_color = get_gtkrc_color(item_edit->sheet, color_type);
color_type = gnc_table_get_gtkrc_fg_color (table,
item_edit->virt_loc);
info->fg_color = get_gtkrc_color(item_edit->sheet, color_type);
}
else
{
argb = gnc_table_get_bg_color (table, item_edit->virt_loc,
&hatching);
info->bg_color = gnucash_color_argb_to_gdk (argb);
argb = gnc_table_get_fg_color (table, item_edit->virt_loc);
info->fg_color = gnucash_color_argb_to_gdk (argb);
}
info->hatching = hatching;
info->fg_color = &gn_black;
info->bg_color2 = &gn_dark_gray;
info->fg_color2 = &gn_white;

View File

@ -2609,31 +2609,49 @@ get_gtkrc_color (GnucashSheet *sheet,
{
GtkWidget *widget = NULL;
GtkStyle *style;
GdkColor *white;
GdkColor *white, *black, *red;
GdkColor *color = NULL;
white = gnucash_color_argb_to_gdk (0xFFFFFF);
black = gnucash_color_argb_to_gdk (0x000000);
red = gnucash_color_argb_to_gdk (0xFF0000); /* Hardcoded...*/
switch (field_type)
{
default:
return white;
case COLOR_HEADER:
case COLOR_UNKNOWN_BG:
return white;
case COLOR_UNKNOWN_FG:
return black;
case COLOR_NEGATIVE:
return red;
case COLOR_HEADER_BG:
case COLOR_HEADER_FG:
widget = sheet->header_color;
break;
case COLOR_PRIMARY:
case COLOR_PRIMARY_ACTIVE:
case COLOR_PRIMARY_BG:
case COLOR_PRIMARY_BG_ACTIVE:
case COLOR_PRIMARY_FG:
case COLOR_PRIMARY_FG_ACTIVE:
widget = sheet->primary_color;
break;
case COLOR_SECONDARY:
case COLOR_SECONDARY_ACTIVE:
case COLOR_SECONDARY_BG:
case COLOR_SECONDARY_BG_ACTIVE:
case COLOR_SECONDARY_FG:
case COLOR_SECONDARY_FG_ACTIVE:
widget = sheet->secondary_color;
break;
case COLOR_SPLIT:
case COLOR_SPLIT_ACTIVE:
case COLOR_SPLIT_BG:
case COLOR_SPLIT_BG_ACTIVE:
case COLOR_SPLIT_FG:
case COLOR_SPLIT_FG_ACTIVE:
widget = sheet->split_color;
break;
}
@ -2647,18 +2665,31 @@ get_gtkrc_color (GnucashSheet *sheet,
default:
return white;
case COLOR_HEADER:
case COLOR_PRIMARY:
case COLOR_SECONDARY:
case COLOR_SPLIT:
case COLOR_HEADER_BG:
case COLOR_PRIMARY_BG:
case COLOR_SECONDARY_BG:
case COLOR_SPLIT_BG:
color = &style->base[GTK_STATE_NORMAL];
break;
case COLOR_PRIMARY_ACTIVE:
case COLOR_SECONDARY_ACTIVE:
case COLOR_SPLIT_ACTIVE:
case COLOR_PRIMARY_BG_ACTIVE:
case COLOR_SECONDARY_BG_ACTIVE:
case COLOR_SPLIT_BG_ACTIVE:
color = &style->base[GTK_STATE_SELECTED];
break;
case COLOR_HEADER_FG:
case COLOR_PRIMARY_FG:
case COLOR_SECONDARY_FG:
case COLOR_SPLIT_FG:
color = &style->text[GTK_STATE_NORMAL];
break;
case COLOR_PRIMARY_FG_ACTIVE:
case COLOR_SECONDARY_FG_ACTIVE:
case COLOR_SPLIT_FG_ACTIVE:
color = &style->text[GTK_STATE_SELECTED];
break;
}
gnucash_color_alloc_gdk(color);