/*
 * This is called when something is entered in the location entry.
 * We either go there (if the text refers to a cell by address or
 * name), or we try to define a name for the selection.
 */
gboolean
wb_control_parse_and_jump (WorkbookControl *wbc, char const *text)
{
	Sheet *sheet = wb_control_cur_sheet (wbc);
	GnmParsePos pp;
	GnmEvalPos ep;
	GnmValue *target;
	GnmRangeRef range;
	SheetView *sv;

	if (text == NULL || *text == '\0')
		return FALSE;

	sv = wb_control_cur_sheet_view (wbc);
	parse_pos_init_editpos (&pp, sv);
	target = value_new_cellrange_parsepos_str (&pp, text,
						   GNM_EXPR_PARSE_DEFAULT);
	if (target == NULL) {
		/* Not an address; is it a name? */
		GnmParsePos pp;
		GnmNamedExpr *nexpr = expr_name_lookup (
			parse_pos_init_sheet (&pp, sheet), text);

		/* If no name, or just a placeholder exists create a name */
		if (nexpr == NULL || expr_name_is_placeholder (nexpr)) {
			wb_create_name (wbc, text, &pp);
			return FALSE;
		} else {
			target = gnm_expr_top_get_range (nexpr->texpr);
			if (target == NULL) {
				go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc),
					_("Address"), text);
				return FALSE;
			}
		}
	}

	eval_pos_init_editpos (&ep, sv);
	gnm_cellref_make_abs (&range.a, &target->v_range.cell.a, &ep);
	gnm_cellref_make_abs (&range.b, &target->v_range.cell.b, &ep);
	value_release (target);

	return wb_control_jump (wbc, sheet, &range);
}
static GtkWidget *
vcombo_create_list (SheetObject *so,
		    GtkTreePath **clip, GtkTreePath **select, gboolean *make_buttons)
{
	GnmValidationCombo *vcombo = GNM_VALIDATION_COMBO (so);
	unsigned	 i;
	UniqueCollection uc;
	GnmEvalPos	 ep;
	GtkTreeIter	 iter;
	GtkWidget	*list;
	GPtrArray	*sorted;
	GtkListStore	*model;
	GnmValue	*v;
	GnmValue const	*cur_val;
	GnmValidation const *val = vcombo->validation;
	SheetView const *sv = vcombo->parent.sv;

	g_return_val_if_fail (val != NULL, NULL);
	g_return_val_if_fail (val->type == GNM_VALIDATION_TYPE_IN_LIST, NULL);
	g_return_val_if_fail (val->deps[0].texpr != NULL, NULL);
	g_return_val_if_fail (sv != NULL, NULL);

	eval_pos_init_editpos (&ep, sv);
	v = gnm_expr_top_eval (val->deps[0].texpr, &ep,
			       GNM_EXPR_EVAL_PERMIT_NON_SCALAR |
			       GNM_EXPR_EVAL_PERMIT_EMPTY |
			       GNM_EXPR_EVAL_ARRAY_CONTEXT);
	if (NULL == v)
		return NULL;

	uc.date_conv = workbook_date_conv (sv->sheet->workbook);
	uc.hash = g_hash_table_new_full ((GHashFunc)value_hash, (GEqualFunc)value_equal,
		(GDestroyNotify)value_release, (GDestroyNotify)g_free);
	value_area_foreach (v, &ep, CELL_ITER_IGNORE_BLANK,
		 (GnmValueIterFunc) cb_collect_unique, &uc);
	value_release (v);

	sorted = g_ptr_array_new ();
	g_hash_table_foreach (uc.hash, (GHFunc)cb_hash_domain, sorted);
	qsort (&g_ptr_array_index (sorted, 0),
	       sorted->len, sizeof (char *),
	       &value_cmp);

	model = gtk_list_store_new (3,
		G_TYPE_STRING, G_TYPE_STRING, gnm_value_get_type ());

	cur_val = sheet_cell_get_value (ep.sheet, ep.eval.col, ep.eval.row);
	for (i = 0; i < sorted->len ; i++) {
		char *label = NULL;
		unsigned const max = 50;
		char const *str = g_hash_table_lookup (uc.hash,
			(v = g_ptr_array_index (sorted, i)));
		gsize len = g_utf8_strlen (str, -1);

		if (len > max + 3) {
			label = g_strdup (str);
			strcpy (g_utf8_offset_to_pointer (label, max), "...");
		}

		gtk_list_store_append (model, &iter);
		gtk_list_store_set (model, &iter,
				    0, label ? label : str, /* Menu text */
				    1, str, /* Actual string selected on.  */
				    -1);
		g_free (label);
		if (i == 10)
			*clip = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
		if (cur_val != NULL && v != NULL && value_equal	(cur_val, v)) {
			gtk_tree_path_free (*select);
			*select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
		}
	}

	g_hash_table_destroy (uc.hash);
	g_ptr_array_free (sorted, TRUE);

	list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
	g_object_unref (model);
	gtk_tree_view_append_column (GTK_TREE_VIEW (list),
		gtk_tree_view_column_new_with_attributes ("ID",
			gtk_cell_renderer_text_new (), "text", 0,
			NULL));
	return list;
}