Exemple #1
0
/**
 * parse_criteria:
 * @crit_val: #GnmValue
 * @date_conv: #GODateConventions
 *
 * Returns: (transfer full): GnmCriteria which caller must free.
 *
 * ">=value"
 * "<=value"
 * "<>value"
 * "<value"
 * ">value"
 * "=value"
 * "pattern"
 **/
GnmCriteria *
parse_criteria (GnmValue const *crit_val, GODateConventions const *date_conv,
		gboolean anchor_end)
{
	int len;
	char const *criteria;
	GnmCriteria *res = g_new0 (GnmCriteria, 1);
	GnmValue *empty;

	res->iter_flags = CELL_ITER_IGNORE_BLANK;
	res->date_conv = date_conv;

	if (VALUE_IS_NUMBER (crit_val)) {
		res->fun = criteria_test_equal;
		res->x = value_dup (crit_val);
		return res;
	}

	criteria = value_peek_string (crit_val);
        if (strncmp (criteria, "<=", 2) == 0) {
		res->fun = criteria_test_less_or_equal;
		len = 2;
	} else if (strncmp (criteria, ">=", 2) == 0) {
		res->fun = criteria_test_greater_or_equal;
		len = 2;
	} else if (strncmp (criteria, "<>", 2) == 0) {
		/* "<>" by itself is special: */
		res->fun = (criteria[2] == 0) ? criteria_test_nonempty : criteria_test_unequal;
		len = 2;
	} else if (*criteria == '<') {
		res->fun = criteria_test_less;
		len = 1;
	} else if (*criteria == '=') {
		/* "=" by itself is special: */
		res->fun = (criteria[1] == 0) ? criteria_test_empty : criteria_test_equal;
		len = 1;
	} else if (*criteria == '>') {
		res->fun = criteria_test_greater;
		len = 1;
	} else {
		res->fun = criteria_test_match;
		res->has_rx = (gnm_regcomp_XL (&res->rx, criteria, GO_REG_ICASE, TRUE, anchor_end) == GO_REG_OK);
		len = 0;
	}

	res->x = format_match_number (criteria + len, NULL, date_conv);
	if (res->x == NULL)
		res->x = value_new_string (criteria + len);
	else if (len == 0 && VALUE_IS_NUMBER (res->x))
		res->fun = criteria_test_equal;

	empty = value_new_empty ();
	if (res->fun (empty, res))
		res->iter_flags &= ~CELL_ITER_IGNORE_BLANK;
	value_release (empty);
	res->ref_count = 1;

	return res;
}
Exemple #2
0
static CritType
criteria_inspect_values (GnmValue const *x, gnm_float *xr, gnm_float *yr,
			 GnmCriteria *crit, gboolean coerce_to_float)
{
	GnmValue const *y = crit->x;

	if (x == NULL || y == NULL)
		return CRIT_NULL;

	switch (y->v_any.type) {
	case VALUE_BOOLEAN:
		/* If we're searching for a bool -- even one that is
		   from a string search value -- we match only bools.  */
		if (!VALUE_IS_BOOLEAN (x))
			return CRIT_WRONGTYPE;
		*xr = value_get_as_float (x);
		*yr = value_get_as_float (y);
		return CRIT_FLOAT;

	case VALUE_EMPTY:
		return CRIT_WRONGTYPE;

	case VALUE_STRING:
		if (!VALUE_IS_STRING (x))
			return CRIT_WRONGTYPE;
		return CRIT_STRING;

	default:
		g_warning ("This should not happen.  Please report.");
		return CRIT_WRONGTYPE;

	case VALUE_FLOAT: {
		GnmValue *vx;
		*yr = value_get_as_float (y);

		if (VALUE_IS_BOOLEAN (x) || VALUE_IS_ERROR (x))
			return CRIT_WRONGTYPE;
		else if (VALUE_IS_FLOAT (x)) {
			*xr = value_get_as_float (x);
			return CRIT_FLOAT;
		}

		if (!coerce_to_float)
			return CRIT_WRONGTYPE;

		vx = format_match (value_peek_string (x), NULL, crit->date_conv);
		if (VALUE_IS_EMPTY (vx) ||
		    VALUE_IS_BOOLEAN (y) != VALUE_IS_BOOLEAN (vx)) {
			value_release (vx);
			return CRIT_WRONGTYPE;
		}

		*xr = value_get_as_float (vx);
		value_release (vx);
		return CRIT_FLOAT;
	}
	}
}
Exemple #3
0
static gboolean
criteria_test_unequal (GnmValue const *x, GnmCriteria *crit)
{
	gnm_float xf, yf;

	switch (criteria_inspect_values (x, &xf, &yf, crit, FALSE)) {
	default:
		g_assert_not_reached ();
	case CRIT_NULL:
	case CRIT_WRONGTYPE:
		return TRUE;
	case CRIT_FLOAT:
		return xf != yf;
	case CRIT_STRING:
		/* FIXME: _ascii_??? */
		return g_ascii_strcasecmp (value_peek_string (x),
					   value_peek_string (crit->x)) != 0;
	}
}
Exemple #4
0
static void
cb_index_cell (G_GNUC_UNUSED gpointer ignore,
	       GnmCell const *cell, IndexerState *state)
{
	if (cell->value != NULL && VALUE_IS_STRING (cell->value)) {
		char const *str = value_peek_string (cell->value);
		if (str != NULL && *str)
			gsf_xml_out_simple_element (state->output, "data", str);
	}
}
Exemple #5
0
static gboolean
criteria_test_greater_or_equal (GnmValue const *x, GnmCriteria *crit)
{
	gnm_float xf, yf;
	GnmValue const *y = crit->x;

	switch (criteria_inspect_values (x, &xf, &yf, crit, FALSE)) {
	default:
		g_assert_not_reached ();
	case CRIT_NULL:
	case CRIT_WRONGTYPE:
		return FALSE;
	case CRIT_STRING:
		return go_utf8_collate_casefold (value_peek_string (x),
						 value_peek_string (y)) >= 0;
	case CRIT_FLOAT:
		return xf >= yf;
	}
}
Exemple #6
0
/*
 * Finds a column index of a field.
 */
int
find_column_of_field (GnmEvalPos const *ep,
		      GnmValue const *database, GnmValue const *field)
{
        Sheet *sheet;
        GnmCell  *cell;
	gchar *field_name;
	int   begin_col, end_col, row, n, column;
	int   offset;

	// I'm not certain we should demand this, but the code clearly wants
	// it.
	if (!VALUE_IS_CELLRANGE (database))
		return -1;

	offset = database->v_range.cell.a.col;

	if (VALUE_IS_FLOAT (field))
		return value_get_as_int (field) + offset - 1;

	if (!VALUE_IS_STRING (field))
		return -1;

	sheet = eval_sheet (database->v_range.cell.a.sheet, ep->sheet);
	field_name = value_get_as_string (field);
	column = -1;

	/* find the column that is labeled after `field_name' */
	begin_col = database->v_range.cell.a.col;
	end_col = database->v_range.cell.b.col;
	row = database->v_range.cell.a.row;

	for (n = begin_col; n <= end_col; n++) {
		char const *txt;
		gboolean match;

		cell = sheet_cell_get (sheet, n, row);
		if (cell == NULL)
			continue;
		gnm_cell_eval (cell);

		txt = cell->value
			? value_peek_string (cell->value)
			: "";
		match = (g_ascii_strcasecmp (field_name, txt) == 0);
		if (match) {
			column = n;
			break;
		}
	}

	g_free (field_name);
	return column;
}
Exemple #7
0
/**
 * stf_export_cell:
 * @stfe: an export options struct
 * @cell: the cell to write to the file
 *
 * Return value: return TRUE on success, FALSE otherwise.
 **/
static gboolean
stf_export_cell (GnmStfExport *stfe, GnmCell *cell)
{
	char const *text = NULL;
	char *tmp = NULL;
	gboolean ok;
	g_return_val_if_fail (stfe != NULL, FALSE);

	if (cell) {
		switch (stfe->format) {
		case GNM_STF_FORMAT_PRESERVE:
			text = tmp = gnm_cell_get_rendered_text (cell);
			break;
		default:
		case GNM_STF_FORMAT_AUTO:
			if (cell->value) {
				GODateConventions const *date_conv =
					workbook_date_conv (cell->base.sheet->workbook);
				GOFormat const *format = gnm_cell_get_format (cell);
				text = tmp = try_auto_date (cell->value, format, date_conv);
				if (!text)
					text = tmp = try_auto_float (cell->value, format, date_conv);
				if (!text)
					text = value_peek_string (cell->value);
			}
			break;
		case GNM_STF_FORMAT_RAW:
			if (cell->value)
				text = value_peek_string (cell->value);
			break;
		}
	}

	ok = gsf_output_csv_write_field (GSF_OUTPUT_CSV (stfe),
					 text ? text : "",
					 -1);
	g_free (tmp);

	return ok;
}
Exemple #8
0
static gboolean
criteria_test_match (GnmValue const *x, GnmCriteria *crit)
{
	if (!crit->has_rx)
		return FALSE;

	// Only strings are matched
	if (!VALUE_IS_STRING (x))
		return FALSE;

	return go_regexec (&crit->rx, value_peek_string (x), 0, NULL, 0) ==
		GO_REG_OK;
}
Exemple #9
0
/*
 * write_row:
 *
 * @output: the stream
 * @sheet: the gnumeric sheet
 * @row: the row number
 *
 */
static void
write_row (GsfOutput *output, Sheet *sheet, gint row, GnmRange *range)
{
    char const *text = NULL;
    char *formatted_string = NULL;
    GnmCell *cell;
    GnmStyle const *style;

    GODateConventions const *date_conv = sheet->workbook ? workbook_date_conv (sheet->workbook) : NULL;


    gint col;
    for (col = range->start.col; col <= range->end.col; col++) {
        GnmRange const *merge_range;
        GnmCellPos pos;
        pos.col = col;
        pos.row = row;
        merge_range = gnm_sheet_merge_contains_pos  (sheet, &pos);
        if (merge_range != NULL) {
            /* If cell is inside a merged region, we use the
               corner cell of the merged region: */
            cell = sheet_cell_get (sheet, merge_range->start.col, merge_range->start.row);
        } else {
            cell = sheet_cell_get (sheet, col, row);
        }

        if (cell != NULL && cell->value) {
            text = value_peek_string (cell->value);
            pwcsv_print_encoded (output, text);

            style = sheet_style_get (sheet, col, row);
            GOFormat const *format = gnm_style_get_format (style);
            // set col_width to 16-something. This works around gnumeric quirk
            // where, in wider cells, it formats 9,3 as 9,300000000000001
            formatted_string = format_value (format, cell->value, 16, date_conv);
            pwcsv_print_encoded (output, formatted_string);
            html_write_cell_content (output, cell, style, formatted_string);

            g_free (formatted_string);

            /* Without this, we're accumulating lots of heap memory
               on big spreadsheets. */
            gnm_cell_unrender(cell);
        } else {
            gsf_output_puts (output, ",,,");
        }
	}

    gsf_output_puts (output, "\n");
}
Exemple #10
0
static void
render_cell (GString *target, HFRenderInfo *info, char const *args)
{
	gboolean use_repeating = FALSE;

	if (args && ((use_repeating = g_str_has_prefix (args, "rep|"))))
		args += 4;

	if (info->sheet) {
		GnmRangeRef ref;
		GnmValue const *val;
		char const *tmp;
		GnmParsePos ppos;

		parse_pos_init (&ppos, info->sheet->workbook, (Sheet *)info->sheet, 0, 0);
		tmp = rangeref_parse
			(&ref, args, &ppos, sheet_get_conventions (info->sheet));
		if (tmp == NULL || tmp == args) {
			gnm_cellref_init (&ref.a, (Sheet *)(info->sheet), 0, 0, FALSE);
		}

		if (ref.a.row_relative)
			ref.a.row += (use_repeating ?
				      info->top_repeating.row : info->page_area.start.row);
		if (ref.a.col_relative)
			ref.a.col += (use_repeating ?
				      info->top_repeating.col : info->page_area.start.col);

		val = sheet_cell_get_value
			(ref.a.sheet ? ref.a.sheet : (Sheet *)(info->sheet),
			 ref.a.col, ref.a.row);
		if (val != NULL) {
			char const *value;
			value = value_peek_string (val);
			g_string_append (target, value);
		}
	}
	else {
		if (use_repeating)
			g_string_append (target, "[");
		g_string_append (target, args);
		if (use_repeating)
			g_string_append (target, "]");
	}
}
Exemple #11
0
char *
gnm_scenario_get_range_str (const GnmScenario *sc)
{
	GString *str;
	GSList *l;

	g_return_val_if_fail (GNM_IS_SCENARIO (sc), NULL);

	str = g_string_new (NULL);
	for (l = sc->items; l; l = l->next) {
		GnmScenarioItem const *sci = l->data;
		GnmValue const *vrange;
		if (sci->value || !gnm_scenario_item_valid (sci, NULL))
			continue;
		if (str->len)
			g_string_append_c (str, ',');
		vrange = gnm_expr_top_get_constant (sci->dep.texpr);
		g_string_append (str, value_peek_string (vrange));
	}

	return g_string_free (str, FALSE);
}
gnm_float
datetime_value_to_serial_raw (GnmValue const *v, GODateConventions const *conv)
{
	gnm_float serial;

	if (VALUE_IS_NUMBER (v))
		serial = value_get_as_float (v);
	else {
		char const *str = value_peek_string (v);
		GnmValue *conversion = format_match_number (str, go_format_default_date (), conv);

		if (conversion) {
			serial = value_get_as_float (conversion);
			value_release (conversion);
		} else
			serial = G_MAXINT;
	}

	if (serial < 0 && !gnm_datetime_allow_negative ())
		serial = G_MAXINT;

	return serial;
}
Exemple #13
0
/**
 * find_rows_that_match:
 * @sheet: #Sheet
 * @first_col: first column.
 * @first_row: first row.
 * @last_col: last column.
 * @last_row: laset row.
 * @criterias: (element-type GnmDBCriteria): the criteria to use.
 * @unique_only:
 *
 * Finds the rows from the given database that match the criteria.
 * Returns: (element-type int) (transfer full): the list of matching rows.
 **/
GSList *
find_rows_that_match (Sheet *sheet, int first_col, int first_row,
		      int last_col, int last_row,
		      GSList *criterias, gboolean unique_only)
{
	GSList	     *rows = NULL;
	GSList const *crit_ptr, *cond_ptr;
	int        row;
	gboolean   add_flag;
	char const *t1, *t2;
	GnmCell   *test_cell;
	GnmValue const *empty = value_new_empty ();

	for (row = first_row; row <= last_row; row++) {
		add_flag = TRUE;
		for (crit_ptr = criterias; crit_ptr; crit_ptr = crit_ptr->next) {
			GnmDBCriteria const *crit = crit_ptr->data;
			add_flag = TRUE;
			for (cond_ptr = crit->conditions;
			     cond_ptr != NULL ; cond_ptr = cond_ptr->next) {
				GnmCriteria *cond = cond_ptr->data;
				test_cell = sheet_cell_get (sheet, cond->column, row);
				if (test_cell != NULL)
					gnm_cell_eval (test_cell);
				if (!cond->fun (test_cell ? test_cell->value : empty, cond)) {
					add_flag = FALSE;
					break;
				}
			}

			if (add_flag)
				break;
		}
		if (add_flag) {
			gint *p;

			if (unique_only) {
				GSList *c;
				GnmCell   *cell;
				gint    i, trow;

				for (c = rows; c != NULL; c = c->next) {
					trow = *((gint *) c->data);
					for (i = first_col; i <= last_col; i++) {
						test_cell = sheet_cell_get (sheet, i, trow);
						cell = sheet_cell_get (sheet, i, row);

						/* FIXME: this is probably not right, but crashing is more wrong.  */
						if (test_cell == NULL || cell == NULL)
							continue;

						t1 = cell->value
							? value_peek_string (cell->value)
							: "";
						t2 = test_cell->value
							? value_peek_string (test_cell->value)
							: "";
						if (strcmp (t1, t2) != 0)
							goto row_ok;
					}
					goto filter_row;
row_ok:
					;
				}
			}
			p = g_new (gint, 1);
			*p = row;
			rows = g_slist_prepend (rows, (gpointer) p);
filter_row:
			;
		}
	}

	return g_slist_reverse (rows);
}
Exemple #14
0
static GnmValue *
gnumeric_convert (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
        /* Weight and mass constants */
#define one_g_to_sg     0.00006852205001
#define one_g_to_lbm    0.002204622915
#define one_g_to_u      6.02217e+23
#define one_g_to_ozm    0.035273972

	/* Distance constants */
#define one_m_to_mi     (one_m_to_yd / 1760)
#define one_m_to_Nmi    (1 / GNM_const (1852.0))
#define one_m_to_in     (10000 / GNM_const (254.0))
#define one_m_to_ft     (one_m_to_in / 12)
#define one_m_to_yd     (one_m_to_ft / 3)
#define one_m_to_ang    GNM_const (1e10)
#define one_m_to_pica   236.2204724409449
#define one_m_to_Pica   one_m_to_pica * 12

	/* Time constants */
#define one_yr_to_day   365.25
#define one_yr_to_hr    (24 * one_yr_to_day)
#define one_yr_to_mn    (60 * one_yr_to_hr)
#define one_yr_to_sec   (60 * one_yr_to_mn)

	/* Pressure constants */
#define one_Pa_to_atm   0.9869233e-5
#define one_Pa_to_mmHg  0.00750061708

	/* Force constants */
#define one_N_to_dyn    100000
#define one_N_to_lbf    0.224808924

	/* Power constants */
#define one_HP_to_W     745.701

	/* Energy constants */
#define one_J_to_e      9999995.193
#define one_J_to_c      0.239006249
#define one_J_to_cal    0.238846191
#define one_J_to_eV     6.2146e+18
#define one_J_to_HPh    (GNM_const (1.0) / (3600 * one_HP_to_W))
#define one_J_to_Wh     (GNM_const (1.0) / 3600)
#define one_J_to_flb    23.73042222
#define one_J_to_BTU    0.000947815

	/* Magnetism constants */
#define one_T_to_ga     10000

	/* Temperature constants */
	const gnm_float C_K_offset = GNM_const (273.15);

	/* Liquid measure constants */
#define one_tsp_to_tbs  (GNM_const (1.0) / 3)
#define one_tsp_to_oz   (GNM_const (1.0) / 6)
#define one_tsp_to_cup  (GNM_const (1.0) / 48)
#define one_tsp_to_pt   (GNM_const (1.0) / 96)
#define one_tsp_to_qt   (GNM_const (1.0) / 192)
#define one_tsp_to_gal  (GNM_const (1.0) / 768)
#define one_tsp_to_l    0.004929994

	/* Prefixes */
#define yotta  GNM_const (1e+24)
#define zetta  GNM_const (1e+21)
#define exa    GNM_const (1e+18)
#define peta   GNM_const (1e+15)
#define tera   GNM_const (1e+12)
#define giga   GNM_const (1e+09)
#define mega   GNM_const (1e+06)
#define kilo   GNM_const (1e+03)
#define hecto  GNM_const (1e+02)
#define deka   GNM_const (1e+01)
#define deci   GNM_const (1e-01)
#define centi  GNM_const (1e-02)
#define milli  GNM_const (1e-03)
#define micro  GNM_const (1e-06)
#define nano   GNM_const (1e-09)
#define pico   GNM_const (1e-12)
#define femto  GNM_const (1e-15)
#define atto   GNM_const (1e-18)
#define zepto  GNM_const (1e-21)
#define yocto  GNM_const (1e-24)

	static const eng_convert_unit_t weight_units[] = {
	        { "g",    1.0 },
		{ "sg",   one_g_to_sg },
		{ "lbm",  one_g_to_lbm },
		{ "u",    one_g_to_u },
		{ "ozm",  one_g_to_ozm },
		{ NULL,   0.0 }
	};

	static const eng_convert_unit_t distance_units[] = {
	        { "m",    1.0 },
		{ "mi",   one_m_to_mi },
		{ "Nmi",  one_m_to_Nmi },
		{ "in",   one_m_to_in },
		{ "ft",   one_m_to_ft },
		{ "yd",   one_m_to_yd },
		{ "ang",  one_m_to_ang },
		{ "Pica", one_m_to_Pica },
		{ "picapt", one_m_to_Pica },
		{ "pica", one_m_to_pica },
		{ NULL,   0.0 }
	};

	static const eng_convert_unit_t time_units[] = {
	        { "yr",   1.0 },
		{ "day",  one_yr_to_day },
		{ "hr",   one_yr_to_hr },
		{ "mn",   one_yr_to_mn },
		{ "sec",  one_yr_to_sec },
		{ NULL,   0.0 }
	};

	static const eng_convert_unit_t pressure_units[] = {
	        { "Pa",   1.0 },
		{ "atm",  one_Pa_to_atm },
		{ "mmHg", one_Pa_to_mmHg },
		{ NULL,   0.0 }
	};

	static const eng_convert_unit_t force_units[] = {
	        { "N",    1.0 },
		{ "dyn",  one_N_to_dyn },
		{ "lbf",  one_N_to_lbf },
		{ NULL,   0.0 }
	};

	static const eng_convert_unit_t energy_units[] = {
	        { "J",    1.0 },
		{ "e",    one_J_to_e },
		{ "c",    one_J_to_c },
		{ "cal",  one_J_to_cal },
		{ "eV",   one_J_to_eV },
		{ "HPh",  one_J_to_HPh },
		{ "Wh",   one_J_to_Wh },
		{ "flb",  one_J_to_flb },
		{ "BTU",  one_J_to_BTU },
		{ NULL,   0.0 }
	};

	static const eng_convert_unit_t power_units[] = {
	        { "HP",   1.0 },
		{ "W",    one_HP_to_W },
		{ NULL,   0.0 }
	};

	static const eng_convert_unit_t magnetism_units[] = {
	        { "T",    1.0 },
		{ "ga",   one_T_to_ga },
		{ NULL,   0.0 }
	};

	static const eng_convert_unit_t liquid_units[] = {
	        { "tsp",  1.0 },
		{ "tbs",  one_tsp_to_tbs },
		{ "oz",   one_tsp_to_oz },
		{ "cup",  one_tsp_to_cup },
		{ "pt",   one_tsp_to_pt },
		{ "qt",   one_tsp_to_qt },
		{ "gal",  one_tsp_to_gal },
		{ "l",    one_tsp_to_l },
		{ NULL,   0.0 }
	};

	static const eng_convert_unit_t prefixes[] = {
	        { "Y", yotta },
	        { "Z", zetta },
	        { "E", exa },
	        { "P", peta },
	        { "T", tera },
	        { "G", giga },
	        { "M", mega },
	        { "k", kilo },
	        { "h", hecto },
	        { "e", deka },
	        { "d", deci },
	        { "c", centi },
	        { "m", milli },
	        { "u", micro },
	        { "n", nano },
	        { "p", pico },
	        { "f", femto },
	        { "a", atto },
	        { "z", zepto },
	        { "y", yocto },
		{ NULL,0.0 }
	};

	gnm_float n;
	char const *from_unit, *to_unit;
	GnmValue *v;

	n = value_get_as_float (argv[0]);
	from_unit = value_peek_string (argv[1]);
	to_unit = value_peek_string (argv[2]);

	if (strcmp (from_unit, "C") == 0 && strcmp (to_unit, "F") == 0)
	        return value_new_float (n * 9 / 5 + 32);
	else if (strcmp (from_unit, "F") == 0 && strcmp (to_unit, "C") == 0)
	        return value_new_float ((n - 32) * 5 / 9);
	else if (strcmp (from_unit, "F") == 0 && strcmp (to_unit, "F") == 0)
	        return value_new_float (n);
	else if (strcmp (from_unit, "F") == 0 && strcmp (to_unit, "K") == 0)
	        return value_new_float ((n - 32) * 5 / 9 + C_K_offset);
	else if (strcmp (from_unit, "K") == 0 && strcmp (to_unit, "F") == 0)
	        return value_new_float ((n - C_K_offset) * 9 / 5 + 32);
	else if (strcmp (from_unit, "C") == 0 && strcmp (to_unit, "K") == 0)
	        return value_new_float (n + C_K_offset);
	else if (strcmp (from_unit, "K") == 0 && strcmp (to_unit, "C") == 0)
	        return value_new_float (n - C_K_offset);

	if (convert (weight_units, prefixes, from_unit, to_unit, n, &v,
		     ei->pos))
	        return v;
	if (convert (distance_units, prefixes, from_unit, to_unit, n, &v,
		     ei->pos))
	        return v;
	if (convert (time_units, NULL, from_unit, to_unit, n, &v,
		     ei->pos))
	        return v;
	if (convert (pressure_units, prefixes, from_unit, to_unit, n, &v,
		     ei->pos))
	        return v;
	if (convert (force_units, prefixes, from_unit, to_unit, n, &v,
		     ei->pos))
	        return v;
	if (convert (energy_units, prefixes, from_unit, to_unit, n, &v,
		     ei->pos))
	        return v;
	if (convert (power_units, prefixes, from_unit, to_unit, n, &v,
		     ei->pos))
	        return v;
	if (convert (magnetism_units, prefixes, from_unit, to_unit, n, &v,
		     ei->pos))
	        return v;
	if (convert (liquid_units, prefixes, from_unit, to_unit, n, &v,
		     ei->pos))
	        return v;
	if (convert (magnetism_units, prefixes, from_unit, to_unit, n, &v,
		     ei->pos))
	        return v;

	return value_new_error_NA (ei->pos);
}
Exemple #15
0
/**
 * gnm_validation_eval:
 * @wbc:
 * @mstyle:
 * @sheet:
 *
 * validation set in the GnmStyle if applicable.
 **/
ValidationStatus
gnm_validation_eval (WorkbookControl *wbc, GnmStyle const *mstyle,
		 Sheet *sheet, GnmCellPos const *pos, gboolean *showed_dialog)
{
	GnmValidation const *v;
	GnmCell *cell;
	GnmValue *val;
	gnm_float x;
	int nok, i;
	GnmEvalPos ep;

	if (showed_dialog) *showed_dialog = FALSE;

	v = gnm_style_get_validation (mstyle);
	if (v == NULL)
		return GNM_VALIDATION_STATUS_VALID;

	if (v->type == GNM_VALIDATION_TYPE_ANY)
		return GNM_VALIDATION_STATUS_VALID;

	cell = sheet_cell_get (sheet, pos->col, pos->row);
	if (cell != NULL)
		gnm_cell_eval (cell);

	if (gnm_cell_is_empty (cell)) {
		if (v->allow_blank)
			return GNM_VALIDATION_STATUS_VALID;
		BARF (g_strdup_printf (_("Cell %s is not permitted to be blank"),
				       cell_name (cell)));
	}

	val = cell->value;
	switch (val->type) {
	case VALUE_ERROR:
		if (typeinfo[v->type].errors_not_allowed)
			BARF (g_strdup_printf (_("Cell %s is not permitted to contain error values"),
					       cell_name (cell)));
		break;

	case VALUE_BOOLEAN:
		if (typeinfo[v->type].bool_always_ok)
			return GNM_VALIDATION_STATUS_VALID;
		break;

	case VALUE_STRING:
		if (typeinfo[v->type].strings_not_allowed)
			BARF (g_strdup_printf (_("Cell %s is not permitted to contain strings"),
					       cell_name (cell)));
		break;

	default:
		break;
	}

	eval_pos_init_cell (&ep, cell);

	switch (v->type) {
	case GNM_VALIDATION_TYPE_AS_INT:
		x = value_get_as_float (val);
		if (gnm_fake_floor (x) == gnm_fake_ceil (x))
			break;
		else
			BARF (g_strdup_printf (_("'%s' is not an integer"),
					       value_peek_string (val)));

	case GNM_VALIDATION_TYPE_AS_NUMBER:
		x = value_get_as_float (val);
		break;

	case GNM_VALIDATION_TYPE_AS_DATE: /* What the hell does this do?  */
		x = value_get_as_float (val);
		if (x < 0)
			BARF (g_strdup_printf (_("'%s' is not a valid date"),
					       value_peek_string (val)));
		break;


	case GNM_VALIDATION_TYPE_AS_TIME: /* What the hell does this do?  */
		x = value_get_as_float (val);
		break;

	case GNM_VALIDATION_TYPE_IN_LIST: {
		GnmExprTop const *texpr = v->deps[0].texpr;
		if (texpr) {
			GnmValue *list = gnm_expr_top_eval
				(texpr, &ep,
				 GNM_EXPR_EVAL_PERMIT_NON_SCALAR | GNM_EXPR_EVAL_PERMIT_EMPTY);
			GnmValue *res = value_area_foreach (list, &ep, CELL_ITER_IGNORE_BLANK,
				 (GnmValueIterFunc) cb_validate_custom, val);
			value_release (list);
			if (res == NULL) {
				GnmParsePos pp;
				char *expr_str = gnm_expr_top_as_string
					(texpr,
					 parse_pos_init_evalpos (&pp, &ep),
					 ep.sheet->convs);
				char *msg = g_strdup_printf (_("%s does not contain the new value."), expr_str);
				g_free (expr_str);
				BARF (msg);
			}
		}
		return GNM_VALIDATION_STATUS_VALID;
	}

	case GNM_VALIDATION_TYPE_TEXT_LENGTH:
		/* XL appears to use a very basic value->string mapping that
		 * ignores formatting.
		 * eg len (12/13/01) == len (37238) = 5
		 * This seems wrong for
		 */
		x = g_utf8_strlen (value_peek_string (val), -1);
		break;

	case GNM_VALIDATION_TYPE_CUSTOM: {
		gboolean valid;
		GnmExprTop const *texpr = v->deps[0].texpr;

		if (!texpr)
			return GNM_VALIDATION_STATUS_VALID;

		val = gnm_expr_top_eval (texpr, &ep, GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
		valid = value_get_as_bool (val, NULL);
		value_release (val);

		if (valid)
			return GNM_VALIDATION_STATUS_VALID;
		else {
			GnmParsePos pp;
			char *expr_str = gnm_expr_top_as_string
				(texpr,
				 parse_pos_init_evalpos (&pp, &ep),
				 ep.sheet->convs);
			char *msg = g_strdup_printf (_("%s is not true."), expr_str);
			g_free (expr_str);
			BARF (msg);
		}
	}

	default:
		g_assert_not_reached ();
		return GNM_VALIDATION_STATUS_VALID;
	}

	if (v->op == GNM_VALIDATION_OP_NONE)
		return GNM_VALIDATION_STATUS_VALID;

	nok = 0;
	for (i = 0; i < opinfo[v->op].nops; i++) {
		GnmExprTop const *texpr_i = v->deps[i].texpr;
		GnmExprTop const *texpr;
		GnmValue *cres;

		if (!texpr_i) {
			nok++;
			continue;
		}

		texpr = gnm_expr_top_new
			(gnm_expr_new_binary
			 (gnm_expr_new_constant (value_new_float (x)),
			  opinfo[v->op].ops[i],
			  gnm_expr_copy (texpr_i->expr)));
		cres = gnm_expr_top_eval
			(texpr, &ep, GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
		if (value_get_as_bool (cres, NULL))
			nok++;
		value_release (cres);
		gnm_expr_top_unref (texpr);
	}

	if (nok < opinfo[v->op].ntrue)
		BARF (g_strdup_printf (_("%s is out of permitted range"),
				       value_peek_string (val)));

	return GNM_VALIDATION_STATUS_VALID;
}
/**
 * cb_dialog_apply_clicked:
 * @button:
 * @state:
 *
 * Close (destroy) the dialog
 **/
static void
cb_dialog_apply_clicked (G_GNUC_UNUSED GtkWidget *button,
			 GoalSeekState *state)
{
	char *status_str;
	GoalSeekStatus status;
	GnmValue *target;
	GnmRangeRef const *r;
	GOFormat *format;

	if (state->warning_dialog != NULL)
		gtk_widget_destroy (state->warning_dialog);

	/* set up source */
	target = gnm_expr_entry_parse_as_value (state->set_cell_entry,
						state->sheet);
	if (target == NULL) {
		go_gtk_notice_nonmodal_dialog (GTK_WINDOW(state->dialog),
					  &(state->warning_dialog),
					  GTK_MESSAGE_ERROR,
					  _("You should introduce a valid cell "
					    "name in 'Set Cell:'!"));
		gnm_expr_entry_grab_focus (state->set_cell_entry, TRUE);
		return;
	}
	r = &target->v_range.cell;
	state->set_cell = sheet_cell_get (r->a.sheet, r->a.col, r->a.row);
	value_release (target);
	if (state->set_cell == NULL || !gnm_cell_has_expr (state->set_cell)) {
		go_gtk_notice_nonmodal_dialog (GTK_WINDOW(state->dialog),
					  &(state->warning_dialog),
					  GTK_MESSAGE_ERROR,
					  _("The cell named in 'Set Cell:' "
					    "must contain a formula!"));
		gnm_expr_entry_grab_focus (state->set_cell_entry, TRUE);
		return;
	}

	/* set up source */
	target = gnm_expr_entry_parse_as_value (state->change_cell_entry,
						state->sheet);
	if (target == NULL) {
		go_gtk_notice_nonmodal_dialog (GTK_WINDOW(state->dialog),
					  &(state->warning_dialog),
					  GTK_MESSAGE_ERROR,
					  _("You should introduce a valid cell "
					    "name in 'By Changing Cell:'!"));
		gnm_expr_entry_grab_focus (state->change_cell_entry, TRUE);
		return;
	}

	r = &target->v_range.cell;
	state->change_cell = sheet_cell_fetch (r->a.sheet, r->a.col, r->a.row);
	value_release (target);
	if (gnm_cell_has_expr (state->change_cell)) {
		go_gtk_notice_nonmodal_dialog (GTK_WINDOW(state->dialog),
					  &(state->warning_dialog),
					  GTK_MESSAGE_ERROR,
					  _("The cell named in 'By changing cell' "
					    "must not contain a formula."));
		gnm_expr_entry_grab_focus (state->change_cell_entry, TRUE);
		return;
	}


	format = gnm_style_get_format (gnm_cell_get_style (state->set_cell));
	if (entry_to_float_with_format (GTK_ENTRY(state->to_value_entry),
					&state->target_value, TRUE, format)){
		go_gtk_notice_nonmodal_dialog (GTK_WINDOW(state->dialog),
					  &(state->warning_dialog),
					  GTK_MESSAGE_ERROR,
					  _("The value given in 'To Value:' "
					    "is not valid."));
		focus_on_entry (GTK_ENTRY(state->to_value_entry));
		return;
	}

	format = gnm_style_get_format (gnm_cell_get_style (state->change_cell));
	if (entry_to_float_with_format (GTK_ENTRY(state->at_least_entry),
					 &state->xmin, TRUE, format)) {
		state->xmin = -max_range_val;
		gtk_entry_set_text (GTK_ENTRY (state->at_least_entry), "");
	}

	if (entry_to_float_with_format (GTK_ENTRY(state->at_most_entry), &state->xmax,
					TRUE, format)) {
		state->xmax = +max_range_val;
		gtk_entry_set_text (GTK_ENTRY (state->at_most_entry), "");
	}

	if ((state->old_cell != NULL) && (state->old_value != NULL)) {
		sheet_cell_set_value (state->old_cell, state->old_value);
		workbook_recalc (state->wb);
		state->old_value = NULL;
	}
	state->old_cell = state->change_cell;
	state->old_value = value_dup (state->change_cell->value);

	status = gnumeric_goal_seek (state);

	switch (status) {
	case GOAL_SEEK_OK: {
		const char *actual_str;
		const char *solution_str;
		GOFormat *format = go_format_general ();
		GnmValue *error_value = value_new_float (state->target_value -
						      value_get_as_float (state->set_cell->value));
		char *target_str = format_value (format, error_value, NULL, -1,
						 workbook_date_conv (state->wb));
		gtk_label_set_text (GTK_LABEL (state->target_value_label), target_str);
		g_free (target_str);
		value_release (error_value);

		status_str =
			g_strdup_printf (_("Goal seeking with cell %s found a solution."),
					 cell_name (state->set_cell));
		gtk_label_set_text (GTK_LABEL (state->result_label), status_str);
		g_free (status_str);

		/* FIXME?  Do a format?  */
		actual_str = state->set_cell->value
			? value_peek_string (state->set_cell->value)
			: "";
		gtk_label_set_text (GTK_LABEL (state->current_value_label), actual_str);

		solution_str = state->change_cell->value
			? value_peek_string (state->change_cell->value)
			: "";
		gtk_label_set_text (GTK_LABEL (state->solution_label), solution_str);

		break;
	}

	default:
		status_str =
			g_strdup_printf (_("Goal seeking with cell %s did not find a solution."),
					 cell_name (state->set_cell));
		gtk_label_set_text (GTK_LABEL (state->result_label), status_str);
		g_free (status_str);
		gtk_label_set_text (GTK_LABEL (state->current_value_label), "");
		gtk_label_set_text (GTK_LABEL (state->solution_label), "");
		gtk_label_set_text (GTK_LABEL (state->target_value_label), "");
		break;
	}
	state->cancelled = FALSE;

	gtk_widget_show (state->result_table);
	return;
}
Exemple #17
0
/**
 * FIXME: In the long term this needs optimising.
 **/
static GnmValue *
val_to_base (GnmFuncEvalInfo *ei,
	     GnmValue const *value,
	     GnmValue const *aplaces,
	     int src_base, int dest_base,
	     gnm_float min_value, gnm_float max_value,
	     Val2BaseFlags flags)
{
	int digit, min, max, places;
	gnm_float v;
	GString *buffer;
	GnmValue *vstring = NULL;

	g_return_val_if_fail (src_base > 1 && src_base <= 36,
			      value_new_error_VALUE (ei->pos));
	g_return_val_if_fail (dest_base > 1 && dest_base <= 36,
			      value_new_error_VALUE (ei->pos));

	/* func.c ought to take care of this.  */
	if (VALUE_IS_BOOLEAN (value))
		return value_new_error_VALUE (ei->pos);
	if (aplaces && VALUE_IS_BOOLEAN (aplaces))
		return value_new_error_VALUE (ei->pos);

	switch (value->type) {
	default:
		return value_new_error_NUM (ei->pos);

	case VALUE_STRING:
		if (flags & V2B_STRINGS_GENERAL) {
			vstring = format_match_number
				(value_peek_string (value), NULL,
				 workbook_date_conv (ei->pos->sheet->workbook));
			if (!vstring || !VALUE_IS_FLOAT (vstring)) {
				value_release (vstring);
				return value_new_error_VALUE (ei->pos);
			}
		} else {
			char const *str = value_peek_string (value);
			size_t len;
			gboolean hsuffix = FALSE;
			char *err;

			if ((flags & V2B_STRINGS_BLANK_ZERO) && *str == 0)
				str = "0";

			/* This prevents leading spaces, signs, etc, and "".  */
			if (!g_ascii_isalnum (*str))
				return value_new_error_NUM (ei->pos);

			len = strlen (str);
			/* We check length in bytes.  Since we are going to
			   require nothing but digits, that is fine.  */
			if ((flags & V2B_STRINGS_MAXLEN) && len > 10)
				return value_new_error_NUM (ei->pos);

			if (flags & V2B_STRINGS_0XH) {
				if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
					str += 2;
				else if (str[len - 1] == 'h' || str[len - 1] == 'H')
					hsuffix = TRUE;
			}

			v = g_ascii_strtoll (str, &err, src_base);
			if (err == str || err[hsuffix] != 0)
				return value_new_error_NUM (ei->pos);

			if (v < min_value || v > max_value)
				return value_new_error_NUM (ei->pos);

			break;
		}
		/* Fall through.  */

	case VALUE_FLOAT: {
		gnm_float val = gnm_fake_trunc (value_get_as_float (vstring ? vstring : value));
		char buf[GNM_MANT_DIG + 10];
		char *err;

		value_release (vstring);

		if (val < min_value || val > max_value)
			return value_new_error_NUM (ei->pos);

		g_ascii_formatd (buf, sizeof (buf) - 1,
				 "%.0" GNM_FORMAT_f,
				 val);

		v = g_ascii_strtoll (buf, &err, src_base);
		if (*err != 0)
			return value_new_error_NUM (ei->pos);
		break;
	}
	}

	if (src_base != 10) {
		gnm_float b10 = gnm_pow (src_base, 10);
		if (v >= b10 / 2) /* N's complement */
			v = v - b10;
	}

	if (flags & V2B_NUMBER)
		return value_new_float (v);

	if (v < 0) {
		min = 1;
		max = 10;
		v += gnm_pow (dest_base, max);
	} else {
		if (v == 0)
			min = max = 1;
		else
			min = max = (int)(gnm_log (v + 0.5) /
					  gnm_log (dest_base)) + 1;
	}

	if (aplaces) {
		gnm_float fplaces = value_get_as_float (aplaces);
		if (fplaces < min || fplaces > 10)
			return value_new_error_NUM (ei->pos);
		places = (int)fplaces;
		if (v >= 0 && places > max)
			max = places;
	} else
		places = 1;

	buffer = g_string_sized_new (max);
	g_string_set_size (buffer, max);

	for (digit = max - 1; digit >= 0; digit--) {
		int thisdigit = gnm_fmod (v + 0.5, dest_base);
		v = gnm_floor ((v + 0.5) / dest_base);
		buffer->str[digit] =
			thisdigit["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"];
	}

	return value_new_string_nocopy (g_string_free (buffer, FALSE));
}
Exemple #18
0
/**
 * dialog_init:
 * @state:
 *
 * Create the dialog (guru).
 *
 **/
static gboolean
dialog_init (SolverState *state)
{
	GtkGrid *grid;
	GnmSolverParameters *param;
	GtkCellRenderer *renderer;
	GtkListStore *store;
	GtkTreeViewColumn *column;
	GSList *cl;
	GnmCell *target_cell;
	GnmValue const *input;
	int i;

	param = state->sheet->solver_parameters;

	state->gui = gnm_gtk_builder_load ("solver.ui", NULL, GO_CMD_CONTEXT (state->wbcg));
        if (state->gui == NULL)
                return TRUE;

	state->dialog = go_gtk_builder_get_widget (state->gui, "Solver");
        if (state->dialog == NULL)
                return TRUE;

	state->notebook = go_gtk_builder_get_widget (state->gui, "solver_notebook");

	/*  buttons  */
	state->solve_button  = go_gtk_builder_get_widget (state->gui, "solvebutton");
	g_signal_connect (G_OBJECT (state->solve_button), "clicked",
			  G_CALLBACK (cb_dialog_solve_clicked), state);

	state->close_button  = go_gtk_builder_get_widget (state->gui, "closebutton");
	g_signal_connect (G_OBJECT (state->close_button), "clicked",
			  G_CALLBACK (cb_dialog_close_clicked), state);

	state->help_button = go_gtk_builder_get_widget (state->gui, "helpbutton");
	gnm_init_help_button (state->help_button, GNUMERIC_HELP_LINK_SOLVER);

	state->add_button  = go_gtk_builder_get_widget (state->gui, "addbutton");
	gtk_button_set_alignment (GTK_BUTTON (state->add_button), 0.5, .5);
	g_signal_connect_swapped (G_OBJECT (state->add_button), "clicked",
		G_CALLBACK (cb_dialog_add_clicked), state);

	state->change_button = go_gtk_builder_get_widget (state->gui,
						     "changebutton");
	g_signal_connect (G_OBJECT (state->change_button), "clicked",
			  G_CALLBACK (cb_dialog_change_clicked), state);

	state->delete_button = go_gtk_builder_get_widget (state->gui,
						     "deletebutton");
	gtk_button_set_alignment (GTK_BUTTON (state->delete_button), 0.5, .5);
	g_signal_connect (G_OBJECT (state->delete_button), "clicked",
			  G_CALLBACK (cb_dialog_delete_clicked), state);

	state->stop_button = go_gtk_builder_get_widget (state->gui, "stopbutton");
	g_signal_connect_swapped (G_OBJECT (state->stop_button),
				  "clicked", G_CALLBACK (cb_stop_solver),
				  state);

	/* target_entry */
	grid = GTK_GRID (go_gtk_builder_get_widget (state->gui,
						 "parameter-grid"));
	state->target_entry = gnm_expr_entry_new (state->wbcg, TRUE);
	gnm_expr_entry_set_flags (state->target_entry,
		GNM_EE_SINGLE_RANGE |
		GNM_EE_FORCE_ABS_REF |
		GNM_EE_SHEET_OPTIONAL, GNM_EE_MASK);
	gtk_widget_set_hexpand (GTK_WIDGET (state->target_entry), TRUE);
	gtk_grid_attach (grid, GTK_WIDGET (state->target_entry), 1, 0, 2, 1);
	gnm_editable_enters (GTK_WINDOW (state->dialog),
				  GTK_WIDGET (state->target_entry));
	gtk_widget_show (GTK_WIDGET (state->target_entry));
	g_signal_connect_after (G_OBJECT (state->target_entry),	"changed",
			G_CALLBACK (dialog_set_main_button_sensitivity),
				state);

	/* change_cell_entry */
	state->change_cell_entry = gnm_expr_entry_new (state->wbcg, TRUE);
	gnm_expr_entry_set_flags (state->change_cell_entry,
		GNM_EE_SINGLE_RANGE |
		GNM_EE_FORCE_ABS_REF |
		GNM_EE_SHEET_OPTIONAL, GNM_EE_MASK);
	gtk_widget_set_hexpand (GTK_WIDGET (state->change_cell_entry), TRUE);
	gtk_grid_attach (grid,
	                 GTK_WIDGET (state->change_cell_entry), 1, 2, 2, 1);
	gnm_editable_enters (GTK_WINDOW (state->dialog),
				  GTK_WIDGET (state->change_cell_entry));
	gtk_widget_show (GTK_WIDGET (state->change_cell_entry));
	g_signal_connect_after (G_OBJECT (state->change_cell_entry), "changed",
		G_CALLBACK (dialog_set_main_button_sensitivity), state);

	/* Algorithm */
	state->algorithm_combo = GTK_COMBO_BOX
		(go_gtk_builder_get_widget (state->gui, "algorithm_combo"));
	renderer = (GtkCellRenderer*) gtk_cell_renderer_text_new();
	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (state->algorithm_combo), renderer, TRUE);
	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (state->algorithm_combo), renderer,
					"text", 0,
					NULL);
	fill_algorithm_combo (state, param->options.model_type);

	for (i = 0; model_type_group[i]; i++) {
		const char *bname = model_type_group[i];
		GtkWidget *w = go_gtk_builder_get_widget(state->gui, bname);
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
					      param->options.model_type ==
					      (GnmSolverModelType)i);
		g_signal_connect (G_OBJECT (w), "clicked",
				  G_CALLBACK (cb_dialog_model_type_clicked), state);
	}

	/* Options */
	state->max_iter_entry = go_gtk_builder_get_widget (state->gui,
						      "max_iter_entry");
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->max_iter_entry),
				   param->options.max_iter);

	state->max_time_entry = go_gtk_builder_get_widget (state->gui,
						      "max_time_entry");
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->max_time_entry),
				   param->options.max_time_sec);

	state->gradient_order_entry = go_gtk_builder_get_widget (state->gui,
								 "gradient_order_entry");
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->gradient_order_entry),
				   param->options.gradient_order);

	/* lhs_entry */
	grid = GTK_GRID (go_gtk_builder_get_widget (state->gui,
	                                            "constraints-grid"));
	state->lhs.entry = gnm_expr_entry_new (state->wbcg, TRUE);
	gnm_expr_entry_set_flags (state->lhs.entry,
		GNM_EE_SINGLE_RANGE |
		GNM_EE_FORCE_ABS_REF |
		GNM_EE_SHEET_OPTIONAL, GNM_EE_MASK);
	gtk_widget_set_hexpand (GTK_WIDGET (state->lhs.entry), TRUE);
	gtk_grid_attach (grid, GTK_WIDGET (state->lhs.entry), 0, 4, 1, 1);
	state->lhs.label = go_gtk_builder_get_widget (state->gui, "lhs_label");
	gtk_label_set_mnemonic_widget (GTK_LABEL (state->lhs.label),
		GTK_WIDGET (state->lhs.entry));
	gtk_widget_show (GTK_WIDGET (state->lhs.entry));
	g_signal_connect_after (G_OBJECT (state->lhs.entry),
		"changed",
		G_CALLBACK (dialog_set_sec_button_sensitivity), state);
	g_signal_connect_swapped (
		gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state->lhs.entry)),
		"activate", G_CALLBACK (cb_dialog_add_clicked), state);

	/* rhs_entry */
	state->rhs.entry = gnm_expr_entry_new (state->wbcg, TRUE);
	gnm_expr_entry_set_flags (state->rhs.entry,
				  GNM_EE_SINGLE_RANGE |
				  GNM_EE_FORCE_ABS_REF |
				  GNM_EE_SHEET_OPTIONAL |
				  GNM_EE_CONSTANT_ALLOWED,
				  GNM_EE_MASK);
	gtk_widget_set_hexpand (GTK_WIDGET (state->rhs.entry), TRUE);
	gtk_grid_attach (grid, GTK_WIDGET (state->rhs.entry), 2, 4, 1, 1);
	gtk_widget_show (GTK_WIDGET (state->rhs.entry));
	state->rhs.label = go_gtk_builder_get_widget (state->gui, "rhs_label");
	gtk_label_set_mnemonic_widget (
		GTK_LABEL (state->rhs.label), GTK_WIDGET (state->rhs.entry));
	g_signal_connect_after (G_OBJECT (state->rhs.entry),
		"changed",
		G_CALLBACK (dialog_set_sec_button_sensitivity), state);
	g_signal_connect_swapped (
		gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state->rhs.entry)),
		"activate", G_CALLBACK (cb_dialog_add_clicked), state);

	/* type_menu */
	state->type_combo = GTK_COMBO_BOX
		(go_gtk_builder_get_widget (state->gui, "type_menu"));
	gtk_combo_box_set_active (state->type_combo, 0);
	g_signal_connect (state->type_combo, "changed",
			  G_CALLBACK (dialog_set_sec_button_sensitivity),
			  state);

	/* constraint_list */
	state->constraint_list = GTK_TREE_VIEW (go_gtk_builder_get_widget
					    (state->gui, "constraint_list"));

	state->constr = NULL;
	g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (state->constraint_list)), "changed",
			  G_CALLBACK (constraint_select_click), state);
	gtk_tree_view_set_reorderable (state->constraint_list, TRUE);
	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
	gtk_tree_view_set_model (state->constraint_list, GTK_TREE_MODEL(store));
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (
			_("Subject to the Constraints:"),
			renderer, "text", 0, NULL);
	gtk_tree_view_column_set_expand (column, TRUE);
	gtk_tree_view_append_column (state->constraint_list, column);

	{
		GtkWidget *w = GTK_WIDGET (state->constraint_list);
		int width, height, vsep;
		PangoLayout *layout =
			gtk_widget_create_pango_layout (w, "Mg19");

		gtk_widget_style_get (w,
				      "vertical_separator", &vsep,
				      NULL);

		pango_layout_get_pixel_size (layout, &width, &height);
		gtk_widget_set_size_request (w,
					     -1,
					     (2 * height + vsep) * (4 + 1));
		g_object_unref (layout);
	}

/* Loading the old solver specs... from param  */

	for (cl = param->constraints; cl; cl = cl->next) {
		GnmSolverConstraint const *c = cl->data;
		GtkTreeIter iter;
		char *str;

		gtk_list_store_append (store, &iter);
		str = gnm_solver_constraint_as_str (c, state->sheet);
		gtk_list_store_set (store, &iter, 0, str, 1, c, -1);
		g_free (str);
	}
	g_object_unref (store);

	INIT_BOOL_ENTRY ("autoscale_button", options.automatic_scaling);
	INIT_BOOL_ENTRY ("non_neg_button", options.assume_non_negative);
	INIT_BOOL_ENTRY ("all_int_button", options.assume_discrete);
	INIT_BOOL_ENTRY ("program", options.program_report);
	INIT_BOOL_ENTRY ("sensitivity", options.sensitivity_report);

	input = gnm_solver_param_get_input (param);
	if (input != NULL)
		gnm_expr_entry_load_from_text (state->change_cell_entry,
					       value_peek_string (input));
	target_cell = gnm_solver_param_get_target_cell (param);
	if (target_cell)
		gnm_expr_entry_load_from_text (state->target_entry,
					       cell_name (target_cell));
	else {
		SheetView *sv = wb_control_cur_sheet_view
			(GNM_WBC (state->wbcg));
		if (sv) {
			GnmRange first = {sv->edit_pos, sv->edit_pos};
			gnm_expr_entry_load_from_range (state->target_entry,
							state->sheet, &first);
		}
	}

	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
		go_gtk_builder_get_widget(state->gui, "max_button")),
			param->problem_type == GNM_SOLVER_MAXIMIZE);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
		go_gtk_builder_get_widget(state->gui, "min_button")),
			param->problem_type == GNM_SOLVER_MINIMIZE);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
		go_gtk_builder_get_widget(state->gui, "no_scenario")),
			! param->options.add_scenario);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
		go_gtk_builder_get_widget(state->gui, "optimal_scenario")),
			param->options.add_scenario);

	state->scenario_name_entry = go_gtk_builder_get_widget
		(state->gui, "scenario_name_entry");
	gtk_entry_set_text (GTK_ENTRY (state->scenario_name_entry),
			    param->options.scenario_name);

	state->run.status_widget = go_gtk_builder_get_widget (state->gui, "solver_status_label");
	state->run.problem_status_widget = go_gtk_builder_get_widget (state->gui, "problem_status_label");
	state->run.objective_value_widget = go_gtk_builder_get_widget (state->gui, "objective_value_label");
	state->run.timer_widget = go_gtk_builder_get_widget (state->gui, "elapsed_time_label");
	state->run.spinner = go_gtk_builder_get_widget (state->gui, "run_spinner");


/* Done */
	gnm_expr_entry_grab_focus (state->target_entry, FALSE);
	wbcg_set_entry (state->wbcg, state->target_entry);

	dialog_set_main_button_sensitivity (NULL, state);
	dialog_set_sec_button_sensitivity (NULL, state);

/* dialog */
	wbc_gtk_attach_guru (state->wbcg, state->dialog);

	g_signal_connect_swapped (G_OBJECT (state->dialog),
				  "destroy",
				  G_CALLBACK (cb_dialog_solver_destroy),
				  state);
	g_object_set_data_full (G_OBJECT (state->dialog),
				"state", state,
				(GDestroyNotify)unref_state);

	return FALSE;
}
Exemple #19
0
static GnmValue *
callback_function_collect (GnmEvalPos const *ep, GnmValue const *value,
			   void *closure)
{
	gnm_float x = 0;
	collect_floats_t *cl = closure;
	gboolean ignore = FALSE;

	switch (value ? value->type : VALUE_EMPTY) {
	case VALUE_EMPTY:
		if (cl->flags & COLLECT_IGNORE_BLANKS)
			ignore = TRUE;
		else if (cl->flags & COLLECT_ZERO_BLANKS)
			x = 0;
		else
			return value_new_error_VALUE (ep);
		break;

	case VALUE_BOOLEAN:
		if (cl->flags & COLLECT_IGNORE_BOOLS)
			ignore = TRUE;
		else if (cl->flags & COLLECT_ZEROONE_BOOLS)
			x = value_get_as_float (value);
		else
			return value_new_error_VALUE (ep);
		break;

	case VALUE_CELLRANGE :
	case VALUE_ARRAY :
		/* Ranges and arrays are not singleton values treat as errors */

	case VALUE_ERROR:
		if (cl->flags & COLLECT_IGNORE_ERRORS)
			ignore = TRUE;
		else if (cl->flags & COLLECT_ZERO_ERRORS)
			x = 0;
		else
			return value_new_error_VALUE (ep);
		break;

	case VALUE_FLOAT:
		x = value_get_as_float (value);
		break;

	case VALUE_STRING:
		if (cl->flags & COLLECT_COERCE_STRINGS) {
			GnmValue *vc = format_match_number (value_peek_string (value),
							    NULL,
							    cl->date_conv);
			gboolean bad = !vc || VALUE_IS_BOOLEAN (vc);
			if (vc) {
				x = value_get_as_float (vc);
				value_release (vc);
			} else
				x = 0;

			if (bad)
				return value_new_error_VALUE (ep);
		} else if (cl->flags & COLLECT_IGNORE_STRINGS)
			ignore = TRUE;
		else if (cl->flags & COLLECT_ZERO_STRINGS)
			x = 0;
		else
			return value_new_error_VALUE (ep);
		break;

	default:
		g_warning ("Trouble in callback_function_collect. (%d)",
			   value->type);
		ignore = TRUE;
	}

	if (ignore) {
		if (cl->flags & COLLECT_INFO)
			cl->info = g_slist_prepend (cl->info, GUINT_TO_POINTER (cl->count));
		else {
			return NULL;
		}
	}

	if (cl->count == cl->alloc_count) {
		cl->alloc_count = cl->alloc_count * 2 + 20;
		cl->data = g_renew (gnm_float, cl->data, cl->alloc_count);
	}

	cl->data[cl->count++] = x;
	return NULL;
}