static GtkWidget * fcombo_create_list (SheetObject *so, GtkTreePath **clip, GtkTreePath **select, gboolean *make_buttons) { GnmFilterCombo *fcombo = GNM_FILTER_COMBO (so); GnmFilter const *filter = fcombo->filter; GnmRange r = filter->r; Sheet *filtered_sheet; UniqueCollection uc; GtkTreeIter iter; GtkListStore *model; GtkWidget *list; GPtrArray *sorted = g_ptr_array_new (); unsigned i, field_num = gnm_filter_combo_index (fcombo); gboolean is_custom = FALSE; GnmValue const *v; GnmValue const *cur_val = NULL; model = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, gnm_value_get_type ()); gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, _("(All)"), 1, NULL, 2, 1, -1); if (fcombo->cond == NULL || fcombo->cond->op[0] == GNM_FILTER_UNUSED) *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, _("(Top 10...)"), 1, NULL, 2, 10,-1); if (fcombo->cond != NULL && (GNM_FILTER_OP_TYPE_MASK & fcombo->cond->op[0]) == GNM_FILTER_OP_TOP_N) *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); /* default to this we can easily revamp later */ gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, _("(Custom...)"), 1, NULL, 2, 2, -1); if (*select == NULL) { is_custom = TRUE; *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); } r.start.row++; /* r.end.row = XL actually extend to the first non-empty element in the list */ r.end.col = r.start.col += field_num; uc.has_blank = FALSE; uc.hash = g_hash_table_new_full ((GHashFunc)value_hash, (GEqualFunc)formatted_value_equal, (GDestroyNotify)value_release, (GDestroyNotify)g_free); uc.src_sheet = filter->sheet; uc.date_conv = sheet_date_conv (uc.src_sheet); /* We do not want to show items that are filtered by _other_ fields. * The cleanest way to do that is to create a temporary sheet, apply * all of the other conditions to it and use that as the source of visibility. */ if (filter->fields->len > 1) { Workbook *wb = uc.src_sheet->workbook; char *name = workbook_sheet_get_free_name (wb, "DummyFilterPopulate", FALSE, FALSE); filtered_sheet = sheet_new (wb, name, gnm_sheet_get_max_cols (uc.src_sheet), gnm_sheet_get_max_rows (uc.src_sheet)); g_free (name); for (i = 0 ; i < filter->fields->len ; i++) if (i != field_num) gnm_filter_combo_apply (g_ptr_array_index (filter->fields, i), filtered_sheet); sheet_foreach_cell_in_range (filtered_sheet, CELL_ITER_IGNORE_HIDDEN, &r, (CellIterFunc)&cb_collect_content, &uc); g_object_unref (filtered_sheet); } else sheet_foreach_cell_in_range (filter->sheet, CELL_ITER_ALL, &r, (CellIterFunc)&cb_collect_content, &uc); g_hash_table_foreach (uc.hash, (GHFunc)cb_hash_domain, sorted); g_ptr_array_sort (sorted, value_cmp); if (fcombo->cond != NULL && fcombo->cond->op[0] == GNM_FILTER_OP_EQUAL && fcombo->cond->op[1] == GNM_FILTER_UNUSED) { cur_val = fcombo->cond->value[0]; } 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. */ 2, 0, 3, v, -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); } } if (uc.has_blank) { gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, _("(Blanks...)"), 1, NULL, 2, 3, -1); if (fcombo->cond != NULL && fcombo->cond->op[0] == GNM_FILTER_OP_BLANKS) *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, _("(Non Blanks...)"), 1, NULL, 2, 4, -1); if (fcombo->cond != NULL && fcombo->cond->op[0] == GNM_FILTER_OP_NON_BLANKS) *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); } else if (is_custom && fcombo->cond != NULL && (GNM_FILTER_OP_TYPE_MASK & fcombo->cond->op[0]) == GNM_FILTER_OP_BLANKS) { gtk_tree_path_free (*select); *select = NULL; } 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; }
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; }