Commit c8191a8e authored by Jody Goldberg's avatar Jody Goldberg Committed by Jody Goldberg

Initial attempt at expr filters


2002-12-07  Jody Goldberg <jody@gnome.org>

	* src/sheet-filter.c : Initial attempt at expr filters
parent 79779a08
......@@ -72,7 +72,7 @@ Pending Patches
20) Change =IF back to a nodes function to handle the majority case
21) AutoFilter
21.1) clip size for long lists (DONE)
21.2) fix mouse events for scrolled combos
21.2) fix mouse events for scrolled combos (DONE)
21.3) race condition on start (DONE)
21.4) top 10 dialog (DONE)
21.5) top 10 item filters (DONE)
......@@ -81,15 +81,17 @@ Pending Patches
21.8) visual cue that row in part of a filter (DONE)
21.9) visual cue that a field is active (DONE)
21.10) select the current condition in the combos (DONE)
21.11) expression filters
21.11) expression filters (DONE)
21.12) expression dialog (DONE)
21.13) Handle range changes (cut-n-paste or ins/del col/row)
21.14) Handle the relationship between groups and filters (DONE)
21.15) xml import/export
21.16) sax import/export
21.17) Fix cursor redraw after filter (DONE)
21.18) Link filters to Show All menu (DONE)
21.19) Have the show all action clear filter conditions (DONE)
21.16) Fix cursor redraw after filter (DONE)
21.17) Link filters to Show All menu (DONE)
21.18) Have the show all action clear filter conditions (DONE)
21.19) Change value entries in expr dialog into combos
21.20) editable enters for value entries
21.21) drag scroll for value combos
22) Add dirty flags to workbook too, adding a sheet should
make workbook dirty not the new sheet.
......@@ -121,6 +123,7 @@ Possibly Post 1.2 Targets
- input message (Stored)
- Put a pango layout in rendered value
- load/save of external references
- all the merged cell singleton bugs
Probably Post 1.2 Targets
-------------------------
......@@ -176,11 +179,6 @@ Misc stuff that should be fixed
: Handle pasting an expression with an un-qualified sheet local name into
another sheet
- can_try_save_to uses access(). That's bogus in a number of ways: (a) it
checks the wrong permissions in the set[gu]id case. (b) It reports the
wrong result if the path is not readable. The Right Way to do this, is
just to do it. And then check the error code.
- hidden rows/cols
: Make unhide smarter to find hidden regions on either side of selected ranges.
......
2002-12-07 Jody Goldberg <jody@gnome.org>
* src/sheet-filter.c : Initial attempt at expr filters
2002-12-07 Christian Neumair <chris@gnome-de.org>
* src/dialogs/sheet-order.glade: Made "_Duplicate" translatable.
......@@ -13,6 +17,9 @@
2002-12-06 Jody Goldberg <jody@gnome.org>
* src/sheet-filter.c (filter_field_arrow_format) : new to make the
arrow more obviously different.
* src/regutf8.c (gnumeric_regcomp_XL) : moved from
plugins/fn-string/functions.c:search_pattern_to_regexp and turned into
a wrapper.
......
......@@ -21,7 +21,7 @@ Jody:
* More attributes for excel95 objects
* Support pruning 3d references on sheet deletion.
* Clean up some workbook view life cycle issues
* Begin support for auto-filters
* Implement Auto-filters
* Begin support for pivot tables
* Full support for SUBTOTAL magic
* Fix sneaky bug between sheetobjects and frozen panes
......
2002-12-07 Jody Goldberg <jody@gnome.org>
* src/sheet-filter.c : Initial attempt at expr filters
2002-12-07 Christian Neumair <chris@gnome-de.org>
* src/dialogs/sheet-order.glade: Made "_Duplicate" translatable.
......@@ -13,6 +17,9 @@
2002-12-06 Jody Goldberg <jody@gnome.org>
* src/sheet-filter.c (filter_field_arrow_format) : new to make the
arrow more obviously different.
* src/regutf8.c (gnumeric_regcomp_XL) : moved from
plugins/fn-string/functions.c:search_pattern_to_regexp and turned into
a wrapper.
......
2002-12-07 Jody Goldberg <jody@gnome.org>
* src/sheet-filter.c : Initial attempt at expr filters
2002-12-07 Christian Neumair <chris@gnome-de.org>
* src/dialogs/sheet-order.glade: Made "_Duplicate" translatable.
......@@ -13,6 +17,9 @@
2002-12-06 Jody Goldberg <jody@gnome.org>
* src/sheet-filter.c (filter_field_arrow_format) : new to make the
arrow more obviously different.
* src/regutf8.c (gnumeric_regcomp_XL) : moved from
plugins/fn-string/functions.c:search_pattern_to_regexp and turned into
a wrapper.
......
......@@ -2,6 +2,8 @@
* dialog-autofilter.c (init_operator) : new.
(dialog_auto_filter) : init the operators.
(map_op) : new.
(cb_autofilter_ok) : save operators and values.
2002-12-05 Jody Goldberg <jody@gnome.org>
......
......@@ -31,6 +31,7 @@
#include <sheet.h>
#include <value.h>
#include <sheet-filter.h>
#include <number-match.h>
#include <glade/glade.h>
......@@ -59,6 +60,57 @@ cb_autofilter_destroy (AutoFilterState *state)
g_free (state);
}
static Value *
map_op (AutoFilterState *state, GnmFilterOp *op,
char const *op_widget, char const *val_widget)
{
int i;
GtkWidget *w = glade_xml_get_widget (state->gui, val_widget);
char const *txt = gtk_entry_get_text (GTK_ENTRY (w));
Value *v = NULL;
*op = GNM_FILTER_UNUSED;
if (txt == NULL || *txt == '\0')
return NULL;
w = glade_xml_get_widget (state->gui, op_widget);
i = gtk_option_menu_get_history (GTK_OPTION_MENU (w));
switch (i) {
case 0: return NULL;
case 1: *op = GNM_FILTER_OP_EQUAL; break;
case 2: *op = GNM_FILTER_OP_NOT_EQUAL; break;
case 3: *op = GNM_FILTER_OP_GT; break;
case 4: *op = GNM_FILTER_OP_GTE; break;
case 5: *op = GNM_FILTER_OP_LT; break;
case 6: *op = GNM_FILTER_OP_LTE; break;
case 7:
case 8: *op = (i == 8) ? GNM_FILTER_OP_NOT_EQUAL : GNM_FILTER_OP_EQUAL;
v = value_new_string_nocopy (g_strconcat ("*", txt, NULL));
break;
case 9:
case 10: *op = (i == 10) ? GNM_FILTER_OP_NOT_EQUAL : GNM_FILTER_OP_EQUAL;
v = value_new_string_nocopy (g_strconcat (txt, "*", NULL));
break;
case 11:
case 12: *op = (i == 12) ? GNM_FILTER_OP_NOT_EQUAL : GNM_FILTER_OP_EQUAL;
v = value_new_string_nocopy (g_strconcat ("*", txt, "*", NULL));
break;
default :
g_warning ("huh?");
return NULL;
};
if (v == NULL)
v = format_match (txt, NULL);
if (v == NULL)
v = value_new_string (txt);
return v;
}
static void
cb_autofilter_ok (G_GNUC_UNUSED GtkWidget *button,
AutoFilterState *state)
......@@ -67,12 +119,20 @@ cb_autofilter_ok (G_GNUC_UNUSED GtkWidget *button,
GtkWidget *w;
if (state->is_expr) {
int bottom, percentage, count;
w = glade_xml_get_widget (state->gui, "op0");
bottom = gtk_option_menu_get_history (GTK_OPTION_MENU (w));
w = glade_xml_get_widget (state->gui, "op1");
percentage = gtk_option_menu_get_history (GTK_OPTION_MENU (w));
GnmFilterOp op0;
Value *v0 = map_op (state, &op0, "op0", "value0");
if (op0 != GNM_FILTER_UNUSED) {
GnmFilterOp op1;
Value *v1 = map_op (state, &op1, "op1", "value1");
if (op1 != GNM_FILTER_UNUSED) {
w = glade_xml_get_widget (state->gui, "and_button");
cond = gnm_filter_condition_new_double (op0, v0,
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)),
op1, v1);
} else
cond = gnm_filter_condition_new_single (op0, v0);
}
} else {
int bottom, percentage, count;
......
......@@ -36,6 +36,7 @@
#include "number-match.h"
#include "dialogs.h"
#include "regutf8.h"
#include "style-color.h"
#include <libfoocanvas/foo-canvas-widget.h>
#include <gtk/gtk.h>
......@@ -135,7 +136,7 @@ filter_field_update_bounds (SheetObject *so, GObject *view_obj)
SHEET_CONTROL_GUI (sheet_object_view_control (view_obj));
scg_object_view_position (scg, so, coords);
/* clip vertically */
tmp = (coords[3] - coords[1]);
if (tmp > 20.) {
......@@ -194,7 +195,7 @@ cb_filter_button_release (GtkWidget *popup, GdkEventButton *event,
GnmFilterCondition *cond = NULL;
WorkbookControlGUI *wbcg;
GtkWidget *event_widget = gtk_get_event_widget ((GdkEvent *) event);
/* A release inside list accepts */
if (event_widget != GTK_WIDGET (list))
return FALSE;
......@@ -216,7 +217,6 @@ cb_filter_button_release (GtkWidget *popup, GdkEventButton *event,
switch (type) {
case 0 : cond = gnm_filter_condition_new_single (
GNM_FILTER_OP_EQUAL, value_duplicate (val));
set_condition = FALSE;
break;
case 1 : cond = NULL; break; /* unfilter */
case 2 : /* Custom */
......@@ -485,12 +485,24 @@ cb_filter_button_pressed (GtkButton *button, GnmFilterField *field)
gtk_grab_add (popup);
gdk_pointer_grab (popup->window, TRUE,
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK,
GDK_POINTER_MOTION_MASK,
NULL, NULL, GDK_CURRENT_TIME);
}
static void
filter_field_arrow_format (GnmFilterField *field, GtkWidget *arrow)
{
gtk_arrow_set (GTK_ARROW (arrow),
field->cond != NULL ? GTK_ARROW_RIGHT : GTK_ARROW_DOWN,
GTK_SHADOW_IN);
if (field->cond != NULL)
gtk_widget_modify_fg (arrow, GTK_STATE_NORMAL, &gs_yellow);
else
gtk_widget_set_style (arrow, NULL);
}
static GObject *
filter_field_new_view (SheetObject *so, SheetControl *sc, gpointer key)
{
......@@ -505,8 +517,9 @@ filter_field_new_view (SheetObject *so, SheetControl *sc, gpointer key)
NULL);
GTK_WIDGET_UNSET_FLAGS (view_widget, GTK_CAN_FOCUS);
arrow = gtk_arrow_new (field->cond != NULL ? GTK_ARROW_RIGHT : GTK_ARROW_DOWN,
arrow = gtk_arrow_new (field->cond != NULL ? GTK_ARROW_RIGHT : GTK_ARROW_DOWN,
GTK_SHADOW_IN);
filter_field_arrow_format (field, arrow);
gtk_container_add (GTK_CONTAINER (view_widget), arrow);
g_object_set_data (G_OBJECT (view_widget), VIEW_ITEM_ID, view_item);
......@@ -545,10 +558,90 @@ GSF_CLASS (GnmFilterField, filter_field,
/*****************************************************************************/
typedef struct {
GnmFilterCondition const *cond;
Value *val[2];
gnumeric_regex_t regexp[2];
} FilterExpr;
static void
filter_expr_init (FilterExpr *data, unsigned i, GnmFilterCondition const *cond)
{
Value *tmp = cond->value[i];
if (VALUE_IS_STRING (tmp)) {
GnmFilterOp op = cond->op[i];
char const *str = value_peek_string (tmp);
data->val[i] = format_match_number (str, NULL);
if (data->val[i] != NULL)
return;
if ((op == GNM_FILTER_OP_EQUAL || op == GNM_FILTER_OP_NOT_EQUAL) &&
gnumeric_regcomp_XL (data->regexp + i, str, REG_ICASE) == REG_OK)
return;
}
data->val[i] = value_duplicate (tmp);
}
static void
filter_expr_release (FilterExpr *data, unsigned i)
{
if (data->val[i] != NULL)
value_release (data->val[i]);
else
gnumeric_regfree (data->regexp + i);
}
static gboolean
filter_expr_eval (GnmFilterOp op, Value const *src, gnumeric_regex_t const *regexp,
Value *target)
{
ValueCompare cmp;
if (src == NULL) {
char const *str = value_peek_string (target);
regmatch_t rm;
switch (gnumeric_regexec (regexp, str, 1, &rm, 0)) {
case REG_NOMATCH: return op == GNM_FILTER_OP_NOT_EQUAL;
case REG_OK: return op == GNM_FILTER_OP_EQUAL;
default:
g_warning ("Unexpected regexec result");
return FALSE;
}
}
cmp = value_compare (target, src, TRUE);
switch (op) {
case GNM_FILTER_OP_EQUAL : return cmp == IS_EQUAL;
case GNM_FILTER_OP_NOT_EQUAL : return cmp != IS_EQUAL;
case GNM_FILTER_OP_GTE : if (cmp == IS_EQUAL) return TRUE; /* fall */
case GNM_FILTER_OP_GT : return cmp == IS_GREATER;
case GNM_FILTER_OP_LTE : if (cmp == IS_EQUAL) return TRUE; /* fall */
case GNM_FILTER_OP_LT : return cmp == IS_LESS;
default :
g_warning ("Huh?");
return FALSE;
};
}
static Value *
cb_filter_expr (Sheet *sheet, int col, int row, Cell *cell, gpointer data)
cb_filter_expr (Sheet *sheet, int col, int row, Cell *cell,
FilterExpr const *data)
{
#warning TODO
if (cell != NULL) {
gboolean res = filter_expr_eval (data->cond->op[0],
data->val[0], data->regexp + 0, cell->value);
if (data->cond->op[1] != GNM_FILTER_UNUSED) {
if (res && !data->cond->is_and)
return NULL;
res = filter_expr_eval (data->cond->op[1],
data->val[1], data->regexp + 1, cell->value);
}
if (res)
return NULL;
}
colrow_set_visibility (sheet, FALSE, FALSE, row, row);
return NULL;
}
......@@ -611,12 +704,14 @@ static Value *
cb_hide_unwanted_items (Sheet *sheet, int col, int row, Cell *cell,
FilterItems const *data)
{
int i = data->elements;
Value const *v = cell->value;
if (cell != NULL) {
int i = data->elements;
Value const *v = cell->value;
while (i-- > 0)
if (data->vals[i] == v)
return NULL;
while (i-- > 0)
if (data->vals[i] == v)
return NULL;
}
colrow_set_visibility (sheet, FALSE, FALSE, row, row);
return NULL;
}
......@@ -652,7 +747,7 @@ static Value *
cb_hide_unwanted_percentage (Sheet *sheet, int col, int row, Cell *cell,
FilterPercentage const *data)
{
if (VALUE_IS_NUMBER (cell->value)) {
if (cell != NULL && VALUE_IS_NUMBER (cell->value)) {
gnm_float const v = value_get_as_float (cell->value);
if (data->find_max) {
if (v >= data->high)
......@@ -678,12 +773,22 @@ filter_field_apply (GnmFilterField *field)
if (field->cond == NULL ||
field->cond->op[0] == GNM_FILTER_UNUSED)
return;
if (0x10 >= (field->cond->op[0] & GNM_FILTER_OP_TYPE_MASK))
if (0x10 >= (field->cond->op[0] & GNM_FILTER_OP_TYPE_MASK)) {
FilterExpr data;
data.cond = field->cond;
filter_expr_init (&data, 0, field->cond);
if (field->cond->op[1] != GNM_FILTER_UNUSED)
filter_expr_init (&data, 1, field->cond);
sheet_foreach_cell_in_range (filter->dep.sheet,
CELL_ITER_IGNORE_HIDDEN | CELL_ITER_IGNORE_BLANK,
CELL_ITER_IGNORE_HIDDEN,
col, start_row, col, end_row,
cb_filter_expr, field);
else if (field->cond->op[0] == GNM_FILTER_OP_BLANKS)
(CellIterFunc) cb_filter_expr, &data);
filter_expr_release (&data, 0);
if (field->cond->op[1] != GNM_FILTER_UNUSED)
filter_expr_release (&data, 1);
} else if (field->cond->op[0] == GNM_FILTER_OP_BLANKS)
sheet_foreach_cell_in_range (filter->dep.sheet,
CELL_ITER_IGNORE_HIDDEN,
col, start_row, col, end_row,
......@@ -737,9 +842,8 @@ filter_field_set_active (GnmFilterField *field)
SheetObject *so = &field->parent;
for (ptr = so->realized_list; ptr; ptr = ptr->next)
gtk_arrow_set (g_object_get_data (ptr->data, ARROW_ID),
field->cond != NULL ? GTK_ARROW_UP : GTK_ARROW_DOWN,
GTK_SHADOW_IN);
filter_field_arrow_format (field,
g_object_get_data (ptr->data, ARROW_ID));
}
/*************************************************************************/
......
......@@ -82,6 +82,7 @@ union _Value {
#define VALUE_FMT(v) ((v)->v_any.fmt)
#define VALUE_IS_EMPTY(v) (((v) == NULL) || ((v)->type == VALUE_EMPTY))
#define VALUE_IS_EMPTY_OR_ERROR(v) (VALUE_IS_EMPTY(v) || (v)->type == VALUE_ERROR)
#define VALUE_IS_STRING(v) ((v)->type == VALUE_STRING)
#define VALUE_IS_NUMBER(v) (((v)->type == VALUE_INTEGER) || \
((v)->type == VALUE_FLOAT) || \
((v)->type == VALUE_BOOLEAN))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment