Sheet: add new sheet_date_conv convenience function.
[gnumeric.git] / src / widgets / gnm-validation-combo-view.c
blob1781dd9a11b2d035f651d23f0d81a5be352617a5
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * gnm-validation-combo-view.c: A canvas object for Validate from list
5 * in cell combos
7 * Copyright (C) 2006 Jody Goldberg (jody@gnome.org)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) version 3.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 * USA
25 #include <gnumeric-config.h>
26 #include "gnm-validation-combo-view.h"
27 #include "gnm-cell-combo-view-impl.h"
29 #include "validation-combo.h"
30 #include "commands.h"
31 #include "gnm-format.h"
32 #include "workbook-control.h"
33 #include "workbook.h"
34 #include "sheet-control-gui.h"
35 #include "sheet-view.h"
36 #include "sheet.h"
37 #include "cell.h"
38 #include "expr.h"
39 #include "value.h"
41 #include "gnumeric.h"
42 #include <goffice/goffice.h>
43 #include <gsf/gsf-impl-utils.h>
44 #include <gtk/gtk.h>
45 #include <glib/gi18n-lib.h>
46 #include <string.h>
48 static gboolean
49 vcombo_activate (SheetObject *so, GtkTreeView *list, WBCGtk *wbcg,
50 G_GNUC_UNUSED gboolean button)
52 GnmValidationCombo *vcombo = GNM_VALIDATION_COMBO (so);
53 GtkTreeIter iter;
55 if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (list), NULL, &iter)) {
56 SheetView *sv = vcombo->parent.sv;
57 char *strval;
58 gtk_tree_model_get (gtk_tree_view_get_model (list), &iter,
59 1, &strval,
60 -1);
61 cmd_set_text (GNM_WBC (wbcg),
62 sv_sheet (sv), &sv->edit_pos, strval, NULL, TRUE);
63 g_free (strval);
65 return TRUE;
68 typedef struct {
69 GHashTable *hash;
70 GODateConventions const *date_conv;
71 } UniqueCollection;
73 static GnmValue *
74 cb_collect_unique (GnmValueIter const *iter, UniqueCollection *uc)
76 GOFormat const *fmt = (NULL != iter->cell_iter)
77 ? gnm_cell_get_format (iter->cell_iter->cell) : NULL;
78 g_hash_table_replace (uc->hash,
79 value_dup (iter->v),
80 format_value (fmt, iter->v, -1, uc->date_conv));
81 return NULL;
84 static void
85 cb_hash_domain (GnmValue *key, gpointer value, gpointer accum)
87 g_ptr_array_add (accum, key);
90 static GtkWidget *
91 vcombo_create_list (SheetObject *so,
92 GtkTreePath **clip, GtkTreePath **select, gboolean *make_buttons)
94 GnmValidationCombo *vcombo = GNM_VALIDATION_COMBO (so);
95 unsigned i;
96 UniqueCollection uc;
97 GnmEvalPos ep;
98 GtkTreeIter iter;
99 GtkWidget *list;
100 GPtrArray *sorted;
101 GtkListStore *model;
102 GnmValue *v;
103 GnmValue const *cur_val;
104 GnmValidation const *val = vcombo->validation;
105 SheetView const *sv = vcombo->parent.sv;
107 g_return_val_if_fail (val != NULL, NULL);
108 g_return_val_if_fail (val->type == GNM_VALIDATION_TYPE_IN_LIST, NULL);
109 g_return_val_if_fail (val->deps[0].texpr != NULL, NULL);
110 g_return_val_if_fail (sv != NULL, NULL);
112 eval_pos_init_editpos (&ep, sv);
113 v = gnm_expr_top_eval (val->deps[0].texpr, &ep,
114 GNM_EXPR_EVAL_PERMIT_NON_SCALAR |
115 GNM_EXPR_EVAL_PERMIT_EMPTY |
116 GNM_EXPR_EVAL_ARRAY_CONTEXT);
117 if (NULL == v)
118 return NULL;
120 uc.date_conv = sheet_date_conv (sv->sheet);
121 uc.hash = g_hash_table_new_full ((GHashFunc)value_hash, (GEqualFunc)value_equal,
122 (GDestroyNotify)value_release, (GDestroyNotify)g_free);
123 value_area_foreach (v, &ep, CELL_ITER_IGNORE_BLANK,
124 (GnmValueIterFunc) cb_collect_unique, &uc);
125 value_release (v);
127 sorted = g_ptr_array_new ();
128 g_hash_table_foreach (uc.hash, (GHFunc)cb_hash_domain, sorted);
129 g_ptr_array_sort (sorted, value_cmp);
131 model = gtk_list_store_new (3,
132 G_TYPE_STRING, G_TYPE_STRING, gnm_value_get_type ());
134 cur_val = sheet_cell_get_value (ep.sheet, ep.eval.col, ep.eval.row);
135 for (i = 0; i < sorted->len ; i++) {
136 char *label = NULL;
137 unsigned const max = 50;
138 char const *str = g_hash_table_lookup (uc.hash,
139 (v = g_ptr_array_index (sorted, i)));
140 gsize len = g_utf8_strlen (str, -1);
142 if (len > max + 3) {
143 label = g_strdup (str);
144 strcpy (g_utf8_offset_to_pointer (label, max), "...");
147 gtk_list_store_append (model, &iter);
148 gtk_list_store_set (model, &iter,
149 0, label ? label : str, /* Menu text */
150 1, str, /* Actual string selected on. */
151 -1);
152 g_free (label);
153 if (i == 10)
154 *clip = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
155 if (cur_val != NULL && v != NULL && value_equal (cur_val, v)) {
156 gtk_tree_path_free (*select);
157 *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
161 g_hash_table_destroy (uc.hash);
162 g_ptr_array_free (sorted, TRUE);
164 list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
165 g_object_unref (model);
166 gtk_tree_view_append_column (GTK_TREE_VIEW (list),
167 gtk_tree_view_column_new_with_attributes ("ID",
168 gtk_cell_renderer_text_new (), "text", 0,
169 NULL));
170 return list;
173 static GtkWidget *
174 vcombo_create_arrow (G_GNUC_UNUSED SheetObject *so)
176 return gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
179 /*******************************************************************************/
181 /* Somewhat magic.
182 * We do not honour all of the anchor flags. All that is used is the far corner. */
183 static void
184 vcombo_set_bounds (SheetObjectView *sov, double const *coords, gboolean visible)
186 GocGroup *view = GOC_GROUP (sov);
188 if (visible) {
189 double scale = goc_canvas_get_pixels_per_unit (GOC_ITEM (view)->canvas);
190 double h = (coords[3] - coords[1]) + 1.;
191 if (h > 20.) /* clip vertically */
192 h = 20.;
193 h /= scale;
194 goc_item_set (GOC_ITEM (view->children->data),
195 /* put it outside the cell */
196 "x", ((coords[2] >= 0.)? coords[2] / scale: (coords[0] / scale - h + 1.)),
197 "y", coords [3] / scale - h + 1.,
198 "width", h, /* force a square, use h for width too */
199 "height", h,
200 NULL);
201 goc_item_show (GOC_ITEM (view));
202 } else
203 goc_item_hide (GOC_ITEM (view));
206 /****************************************************************************/
208 static void
209 gnm_validation_view_class_init (GnmCComboViewClass *ccombo_class)
211 SheetObjectViewClass *sov_class = (SheetObjectViewClass *) ccombo_class;
212 ccombo_class->create_list = vcombo_create_list;
213 ccombo_class->create_arrow = vcombo_create_arrow;
214 ccombo_class->activate = vcombo_activate;
215 sov_class->set_bounds = vcombo_set_bounds;
218 typedef GnmCComboView GnmValidationComboView;
219 typedef GnmCComboViewClass GnmValidationComboViewClass;
220 GSF_CLASS (GnmValidationComboView, gnm_validation_combo_view,
221 gnm_validation_view_class_init, NULL,
222 GNM_CCOMBO_VIEW_TYPE)