mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Fix bug in gnc_numeric_reduce. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3093 57a11ea4-9604-0410-9ed3-97b8803252fd
390 lines
8.7 KiB
C
390 lines
8.7 KiB
C
/********************************************************************\
|
|
* 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 *
|
|
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
|
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
|
* *
|
|
\********************************************************************/
|
|
|
|
/*
|
|
* FILE:
|
|
* pricecell.c
|
|
*
|
|
* FUNCTION:
|
|
* Implements the price cell
|
|
*
|
|
* HISTORY:
|
|
* Copyright (c) 1998, 1999, 2000 Linas Vepstas
|
|
* Copyright (c) 2000 Dave Peticolas
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <locale.h>
|
|
#include <string.h>
|
|
|
|
#include "gnc-common.h"
|
|
#include "gnc-exp-parser.h"
|
|
#include "util.h"
|
|
|
|
#include "basiccell.h"
|
|
#include "pricecell.h"
|
|
|
|
/* GUI-dependent */
|
|
extern void xaccPriceGUIInit (PriceCell *);
|
|
|
|
static void PriceSetValue (BasicCell *, const char *);
|
|
static const char * xaccPriceCellPrintValue (PriceCell *cell);
|
|
|
|
|
|
/* ================================================ */
|
|
|
|
/* set the color of the text to red, if the value is negative */
|
|
/* hack alert -- the actual color should probably be configurable */
|
|
#define COLORIZE(cell,amount) { \
|
|
if ((0.0 > amount) && !DEQ(amount, 0.0)) { \
|
|
/* red */ \
|
|
cell->cell.fg_color = 0xff0000; \
|
|
} else { \
|
|
/* black */ \
|
|
cell->cell.fg_color = 0x0; \
|
|
} \
|
|
}
|
|
|
|
#define SET(cell,str) { \
|
|
g_free ((cell)->value); \
|
|
(cell)->value = g_strdup (str); \
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
static gboolean
|
|
PriceEnter (BasicCell *_cell,
|
|
int *cursor_position,
|
|
int *start_selection,
|
|
int *end_selection)
|
|
{
|
|
*cursor_position = -1;
|
|
*start_selection = 0;
|
|
*end_selection = -1;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* ================================================ */
|
|
/* This callback only allows numbers with a single
|
|
* decimal point in them */
|
|
|
|
static void
|
|
PriceMV (BasicCell *_cell,
|
|
const char *change,
|
|
const char *newval,
|
|
int *cursor_position,
|
|
int *start_selection,
|
|
int *end_selection)
|
|
{
|
|
PriceCell *cell = (PriceCell *) _cell;
|
|
struct lconv *lc = gnc_localeconv();
|
|
const char *toks = "+-*/=()";
|
|
char decimal_point;
|
|
char thousands_sep;
|
|
int i;
|
|
|
|
/* accept the newval string if user action was delete */
|
|
if (change == NULL)
|
|
{
|
|
SET ((&(cell->cell)), newval);
|
|
cell->need_to_parse = TRUE;
|
|
return;
|
|
}
|
|
|
|
if (cell->monetary)
|
|
decimal_point = lc->mon_decimal_point[0];
|
|
else
|
|
decimal_point = lc->decimal_point[0];
|
|
|
|
if (cell->monetary)
|
|
thousands_sep = lc->mon_thousands_sep[0];
|
|
else
|
|
thousands_sep = lc->thousands_sep[0];
|
|
for (i = 0; change[i] != '\0'; i++)
|
|
if (!isdigit(change[i]) &&
|
|
!isspace(change[i]) &&
|
|
(decimal_point != change[i]) &&
|
|
(thousands_sep != change[i]) &&
|
|
(strchr (toks, change[i]) == NULL))
|
|
return;
|
|
|
|
SET ((&(cell->cell)), newval);
|
|
cell->need_to_parse = TRUE;
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
static void
|
|
PriceParse (PriceCell *cell)
|
|
{
|
|
const char *newval;
|
|
char *oldval;
|
|
gnc_numeric amount;
|
|
|
|
if (!cell->need_to_parse)
|
|
return;
|
|
|
|
oldval = cell->cell.value;
|
|
if (oldval == NULL)
|
|
oldval = "";
|
|
|
|
if (gnc_exp_parser_parse (cell->cell.value, &amount, NULL))
|
|
cell->amount = gnc_numeric_to_double (amount);
|
|
else
|
|
cell->amount = 0.0;
|
|
|
|
COLORIZE (cell, cell->amount);
|
|
|
|
newval = xaccPriceCellPrintValue(cell);
|
|
|
|
/* If they are identical do nothing */
|
|
if (strcmp(newval, oldval) == 0)
|
|
return;
|
|
|
|
/* Otherwise, change it */
|
|
SET ((&(cell->cell)), newval);
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
static void
|
|
PriceLeave (BasicCell *_cell)
|
|
{
|
|
PriceCell *cell = (PriceCell *) _cell;
|
|
|
|
PriceParse (cell);
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
static char *
|
|
PriceHelp (BasicCell *bcell)
|
|
{
|
|
if ((bcell->value != NULL) && (bcell->value[0] != 0))
|
|
{
|
|
const char *help_str;
|
|
|
|
help_str = bcell->value;
|
|
|
|
return g_strdup(help_str);
|
|
}
|
|
|
|
if (bcell->blank_help != NULL)
|
|
return g_strdup(bcell->blank_help);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
PriceCell *
|
|
xaccMallocPriceCell (void)
|
|
{
|
|
PriceCell *cell;
|
|
|
|
cell = g_new(PriceCell, 1);
|
|
|
|
xaccInitPriceCell (cell);
|
|
|
|
return cell;
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
void
|
|
xaccInitPriceCell (PriceCell *cell)
|
|
{
|
|
xaccInitBasicCell (&(cell->cell));
|
|
|
|
cell->amount = 0.0;
|
|
cell->blank_zero = TRUE;
|
|
cell->monetary = TRUE;
|
|
cell->is_currency = FALSE;
|
|
cell->shares_value = FALSE;
|
|
|
|
cell->need_to_parse = FALSE;
|
|
|
|
SET (&(cell->cell), "");
|
|
COLORIZE (cell, 0.0);
|
|
|
|
cell->cell.use_fg_color = TRUE;
|
|
cell->cell.enter_cell = PriceEnter;
|
|
cell->cell.modify_verify = PriceMV;
|
|
cell->cell.leave_cell = PriceLeave;
|
|
cell->cell.set_value = PriceSetValue;
|
|
cell->cell.get_help_value = PriceHelp;
|
|
|
|
xaccPriceGUIInit (cell);
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
void
|
|
xaccDestroyPriceCell (PriceCell *cell)
|
|
{
|
|
cell->amount = 0.0;
|
|
xaccDestroyBasicCell (&(cell->cell));
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
static const char *
|
|
xaccPriceCellPrintValue (PriceCell *cell)
|
|
{
|
|
GNCPrintAmountFlags flags = PRTSEP;
|
|
|
|
if (cell->blank_zero && DEQ(cell->amount, 0.0))
|
|
return "";
|
|
|
|
if (cell->shares_value)
|
|
flags |= PRTSHR;
|
|
|
|
if (cell->is_currency)
|
|
flags |= PRTCUR;
|
|
|
|
return DxaccPrintAmount(cell->amount, flags, NULL);
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
double
|
|
xaccGetPriceCellValue (PriceCell *cell)
|
|
{
|
|
if (cell == NULL)
|
|
return 0.0;
|
|
|
|
PriceParse (cell);
|
|
|
|
return cell->amount;
|
|
}
|
|
|
|
void
|
|
xaccSetPriceCellValue (PriceCell * cell, double amount)
|
|
{
|
|
const char *buff;
|
|
|
|
if (cell == NULL)
|
|
return;
|
|
|
|
cell->amount = amount;
|
|
buff = xaccPriceCellPrintValue (cell);
|
|
cell->need_to_parse = FALSE;
|
|
|
|
SET (&(cell->cell), buff);
|
|
|
|
/* set the cell color to red if the value is negative */
|
|
COLORIZE (cell, amount);
|
|
}
|
|
|
|
void
|
|
xaccSetPriceCellBlank (PriceCell *cell)
|
|
{
|
|
if (cell == NULL)
|
|
return;
|
|
|
|
cell->amount = 0.0;
|
|
cell->need_to_parse = FALSE;
|
|
|
|
SET (&(cell->cell), "");
|
|
|
|
COLORIZE (cell, 0.0);
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
void
|
|
xaccSetPriceCellSharesValue (PriceCell * cell, gboolean shares_value)
|
|
{
|
|
if (cell == NULL)
|
|
return;
|
|
|
|
cell->shares_value = shares_value;
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
void
|
|
xaccSetPriceCellMonetary (PriceCell * cell, gboolean monetary)
|
|
{
|
|
if (cell == NULL)
|
|
return;
|
|
|
|
cell->monetary = monetary;
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
void
|
|
xaccSetPriceCellIsCurrency (PriceCell *cell, gboolean is_currency)
|
|
{
|
|
if (cell == NULL)
|
|
return;
|
|
|
|
cell->is_currency = is_currency;
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
void
|
|
xaccSetPriceCellBlankZero (PriceCell *cell, gboolean blank_zero)
|
|
{
|
|
if (cell == NULL)
|
|
return;
|
|
|
|
cell->blank_zero = blank_zero;
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
void xaccSetDebCredCellValue (PriceCell * debit,
|
|
PriceCell * credit,
|
|
double amount)
|
|
{
|
|
/* debits are positive, credits are negative */
|
|
if (amount > 0.0) {
|
|
xaccSetPriceCellValue (debit, amount);
|
|
xaccSetPriceCellValue (credit, 0.0);
|
|
} else {
|
|
xaccSetPriceCellValue (debit, 0.0);
|
|
xaccSetPriceCellValue (credit, -amount);
|
|
}
|
|
}
|
|
|
|
/* ================================================ */
|
|
|
|
static void
|
|
PriceSetValue (BasicCell *_cell, const char *str)
|
|
{
|
|
PriceCell *cell = (PriceCell *) _cell;
|
|
gnc_numeric amount;
|
|
|
|
if (str == NULL)
|
|
str = "";
|
|
|
|
if (*str == '\0')
|
|
xaccSetPriceCellValue (cell, 0.0);
|
|
else if (gnc_exp_parser_parse (str, &amount, NULL))
|
|
xaccSetPriceCellValue (cell, gnc_numeric_to_double (amount));
|
|
}
|
|
|
|
/* --------------- end of file ---------------------- */
|