예제 #1
0
/*
 * Advanced Filter tool.
 */
gint
advanced_filter (WorkbookControl        *wbc,
		 data_analysis_output_t *dao,
		 GnmValue               *database,
		 GnmValue               *criteria,
		 gboolean               unique_only_flag)
{
        GSList  *crit, *rows;
	GnmEvalPos ep;
	GnmRange r, s;
	SheetView *sv;
	Sheet *sheet = criteria->v_range.cell.a.sheet;

	/* I don't like this -- minimal fix for now.  509427.  */
	if (!VALUE_IS_CELLRANGE (criteria))
		return analysis_tools_invalid_field;

	crit = parse_database_criteria (
		eval_pos_init_sheet (&ep, wb_control_cur_sheet (wbc)),
		database, criteria);

	if (crit == NULL)
		return analysis_tools_invalid_field;

	rows = find_rows_that_match (sheet,
				     database->v_range.cell.a.col,
				     database->v_range.cell.a.row + 1,
				     database->v_range.cell.b.col,
				     database->v_range.cell.b.row,
				     crit, unique_only_flag);

	free_criterias (crit);

	if (rows == NULL)
		return analysis_tools_no_records_found;

	dao_prepare_output (wbc, dao, _("Filtered"));

	filter (dao, sheet, rows,
		database->v_range.cell.a.col,
		database->v_range.cell.b.col, database->v_range.cell.a.row,
		database->v_range.cell.b.row);

	g_slist_free_full (rows, (GDestroyNotify)g_free);

	sv = sheet_get_view (sheet, wb_control_view (wbc));
	s = r = *(selection_first_range (sv, NULL, NULL));
	r.end.row = r.start.row;
	sv_selection_reset (sv);
	sv_selection_add_range (sv, &r);
	sv_selection_add_range (sv, &s);

	wb_control_menu_state_update (wbc, MS_FILTER_STATE_CHANGED);

	return analysis_tools_noerr;
}
예제 #2
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;
}
예제 #3
0
/**
 * value_area_foreach:
 * @v: const #GnmValue
 * @ep: const #GnmEvalPos
 * @flags: #CellIterFlags
 * @func: (scope call): #GnmValueIterFunc
 * @user_data:
 *
 * For each existing element in an array or range , invoke the
 * callback routine.
 *
 * Returns: (transfer none):
 *    non-NULL on error, or VALUE_TERMINATE if some invoked routine requested
 *    to stop (by returning non-NULL).
 **/
GnmValue *
value_area_foreach (GnmValue const *v, GnmEvalPos const *ep,
		    CellIterFlags flags,
		    GnmValueIterFunc func,
		    gpointer user_data)
{
	GnmValueIter v_iter;
	GnmValue    *tmp;

	g_return_val_if_fail (func != NULL, NULL);

        if (VALUE_IS_CELLRANGE (v)) {
		WrapperClosure wrap;
		GnmRange  r;
		Sheet *start_sheet, *end_sheet;

		gnm_rangeref_normalize (&v->v_range.cell, ep, &start_sheet, &end_sheet, &r);

		wrap.v_iter.ep		= ep;
		wrap.v_iter.region	= v;
		wrap.func		= func;
		wrap.user_data		= user_data;
		wrap.base_col		= r.start.col;
		wrap.base_row	= r.start.row;
		return workbook_foreach_cell_in_range (ep, v, flags,
			(CellIterFunc) cb_wrapper_foreach_cell_in_area, &wrap);
	}

	v_iter.ep = ep;
	v_iter.region = v;
	v_iter.cell_iter = NULL;

	/* If not an array, apply func to singleton */
        if (!VALUE_IS_ARRAY (v)) {
		v_iter.x = v_iter.y = 0;
		v_iter.v = v;
		return (*func) (&v_iter, user_data);
	}

	for (v_iter.x = v->v_array.x; v_iter.x-- > 0;)
		for (v_iter.y = v->v_array.y; v_iter.y-- > 0;) {
			v_iter.v = v->v_array.vals [v_iter.x][v_iter.y];
			if ((tmp = (*func)(&v_iter, user_data)) != NULL)
				return tmp;
		}

	return NULL;
}
예제 #4
0
int
value_area_get_width (GnmValue const *v, GnmEvalPos const *ep)
{
	g_return_val_if_fail (v, 0);

	if (VALUE_IS_CELLRANGE (v)) {
		GnmRange r;
		Sheet *start_sheet, *end_sheet;

		g_return_val_if_fail (ep, 0);
		gnm_rangeref_normalize (&v->v_range.cell, ep, &start_sheet, &end_sheet, &r);
		return range_width (&r);
	} else if (VALUE_IS_ARRAY (v))
		return v->v_array.x;
	return 1;
}
예제 #5
0
파일: scenarios.c 프로젝트: nzinfo/gnumeric
gboolean
gnm_scenario_item_valid (const GnmScenarioItem *sci, GnmSheetRange *sr)
{
	GnmExprTop const *texpr;
	GnmValue const *vr;

	if (!sci || !((texpr = sci->dep.texpr)))
		return FALSE;

	vr = gnm_expr_top_get_constant (texpr);
	if (!vr || !VALUE_IS_CELLRANGE (vr))
		return FALSE;

	if (sr)
		gnm_sheet_range_from_value
			(sr, gnm_expr_top_get_constant (texpr));
	return TRUE;
}
예제 #6
0
/**
 * parse_database_criteria:
 * @ep: #GnmEvalPos
 * @database: #GnmValue
 * @criteria: #GnmValue
 *
 * Parses the criteria cell range.
 * Returns: (element-type GnmDBCriteria) (transfer full):
 */
GSList *
parse_database_criteria (GnmEvalPos const *ep, GnmValue const *database, GnmValue const *criteria)
{
	Sheet	*sheet;
	GnmCell	*cell;
        int   i;
	int   b_col, b_row, e_col, e_row;
	int   *field_ind;

	g_return_val_if_fail (VALUE_IS_CELLRANGE (criteria), NULL);

	sheet = eval_sheet (criteria->v_range.cell.a.sheet, ep->sheet);
	b_col = criteria->v_range.cell.a.col;
	b_row = criteria->v_range.cell.a.row;
	e_col = criteria->v_range.cell.b.col;
	e_row = criteria->v_range.cell.b.row;

	if (e_col < b_col) {
		int tmp = b_col;
		b_col = e_col;
		e_col = tmp;
	}

	/* Find the index numbers for the columns of criterias */
	field_ind = g_alloca (sizeof (int) * (e_col - b_col + 1));
	for (i = b_col; i <= e_col; i++) {
		cell = sheet_cell_get (sheet, i, b_row);
		if (cell == NULL)
			continue;
		gnm_cell_eval (cell);
		if (gnm_cell_is_empty (cell))
			continue;
		field_ind[i - b_col] =
			find_column_of_field (ep, database, cell->value);
		if (field_ind[i - b_col] == -1)
			return NULL;
	}

	return parse_criteria_range (sheet, b_col, b_row + 1,
				     e_col, e_row, field_ind,
				     FALSE);
}
예제 #7
0
파일: collect.c 프로젝트: nzinfo/gnumeric
/**
 * collect_float_pairs:
 * @v0: value describing first data range
 * @v1: value describing second data range
 * @ep: evaluation position
 * @flags: flags describing how to handle value types
 * @xs0: return location for first data vector
 * @xs1: return location for second data vector
 * @n: return location for number of data points
 * @constp: optional return location for an indicator of the return vectors
 * being owned by this function as opposed to the normal copy owned by the
 * caller.
 *
 * If @n is not positive upon return, no data has been allocated.
 * If @n is negative upon return, the two ranges had different
 * sizes.
 */
GnmValue *
collect_float_pairs (GnmValue const *vx, GnmValue const *vy,
		     GnmEvalPos const *ep, CollectFlags flags,
		     gnm_float **xs0, gnm_float **xs1, int *n,
		     gboolean *constp)
{
	GnmValue *key_x = NULL;
	GnmValue *key_y = NULL;
	PairsFloatsCacheEntry *ce = NULL;
	gboolean use_cache, free_keys = TRUE;

	if (VALUE_IS_CELLRANGE (vx))
		key_x = get_single_cache_key_from_value (vx, ep);
	if (VALUE_IS_CELLRANGE (vy))
		key_y = get_single_cache_key_from_value (vy, ep);

	if ((use_cache = (key_x && key_y)))
		ce = get_or_fake_pairs_cache_entry (key_x, key_y, flags, ep);

	if (!ce) {
		ce = collect_float_pairs_ce (vx, vy, ep, flags);
		if (use_cache) {
			PairsFloatsCacheEntry *ce2;
			ce->vx = key_x;
			ce->vy = key_y;
			free_keys = FALSE;

			/*
			 * We looked for the entry earlier and it was not there.
			 * However, sub-calculation might have added it so be careful
			 * to adjust sizes and replace the not-so-old entry.
			 * See bug 627079.
			 */
			ce2 = g_hash_table_lookup (pairs_floats_cache, ce);
			if (ce2)
				total_cache_size -= 1 + ce2->n;

			g_hash_table_replace (pairs_floats_cache, ce, ce);
			total_cache_size += 1 + ce->n;
		}
	}

	if (free_keys) {
		value_release (key_x);
		value_release (key_y);
	}

	if (ce == NULL)
		return value_new_error_VALUE (ep);
	else {
		if (ce->error) {
			if (use_cache)
				return value_dup (ce->error);
			else {
				GnmValue *ret = ce->error;
				ce->error = NULL;
				pairs_floats_cache_entry_free (ce);
				return ret;
			}
		}
		*n = ce->n;
		if (ce->n <= 0) {
			if (!use_cache)
				pairs_floats_cache_entry_free (ce);
			*xs0 = NULL;
			*xs1 = NULL;
			if (constp)
				*constp = FALSE;
			return NULL;
		}
		if (use_cache) {
			if (constp) {
				*xs0 = ce->data_x;
				*xs1 = ce->data_y;
				*constp = TRUE;
			} else {
				*xs0 = g_memdup (ce->data_x, *n * sizeof (gnm_float));
				*xs1 = g_memdup (ce->data_y, *n * sizeof (gnm_float));
			}
		} else {
			if (constp)
				*constp = FALSE;
			*xs0 = ce->data_x;
			*xs1 = ce->data_y;
			ce->data_x = NULL;
			ce->data_y = NULL;
			pairs_floats_cache_entry_free (ce);
		}
		return NULL;
	}
}
예제 #8
0
/**
 * value_area_get_x_y:
 * @v: const #GnmValue *
 * @x: column
 * @y: row
 * @ep: const #GnmEvalPos *
 *
 * An internal routine to get a cell from an array or range.
 * Ensures that elements of CELLRANGE are evaluated
 *
 * If any problems occur a NULL is returned.
 **/
GnmValue const *
value_area_get_x_y (GnmValue const *v, int x, int y, GnmEvalPos const *ep)
{
	g_return_val_if_fail (v, NULL);

	if (VALUE_IS_ARRAY (v)){
		g_return_val_if_fail (x < v->v_array.x &&
				      y < v->v_array.y,
				      NULL);
		return v->v_array.vals [x][y];
	} else if (VALUE_IS_CELLRANGE (v)) {
		GnmCellRef const * const a = &v->v_range.cell.a;
		GnmCellRef const * const b = &v->v_range.cell.b;
		int a_col = a->col;
		int a_row = a->row;
		int b_col = b->col;
		int b_row = b->row;
		GnmCell *cell;
		Sheet *sheet;

		/* Handle relative references */
		if (a->col_relative)
			a_col += ep->eval.col;
		if (a->row_relative)
			a_row += ep->eval.row;
		if (b->col_relative)
			b_col += ep->eval.col;
		if (b->row_relative)
			b_row += ep->eval.row;

		/* Handle inverted references */
		if (a_row > b_row) {
			int tmp = a_row;
			a_row = b_row;
			b_row = tmp;
		}
		if (a_col > b_col) {
			int tmp = a_col;
			a_col = b_col;
			b_col = tmp;
		}

		a_col += x;
		a_row += y;

		/*
		 * FIXME FIXME FIXME
		 * This should return NA but some of the math functions may
		 * rely on this for now.
		 */
		g_return_val_if_fail (a_row<=b_row, NULL);
		g_return_val_if_fail (a_col<=b_col, NULL);

		sheet = eval_sheet (a->sheet, ep->sheet);

		g_return_val_if_fail (IS_SHEET (sheet), NULL);

		/* Speedup */
		if (sheet->cols.max_used < a_col ||
		    sheet->rows.max_used < a_row)
			return value_new_empty ();

		cell = sheet_cell_get (sheet, a_col, a_row);
		if (cell != NULL) {
			gnm_cell_eval (cell);
			return cell->value;
		}

		return value_new_empty ();
	} else
		return v;

	return NULL;
}