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

new. (dialog_auto_filter) : init the operators.

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

	* dialog-autofilter.c (init_operator) : new.
	(dialog_auto_filter) : init the operators.

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

	* src/regutf8.c (gnumeric_regcomp_XL) : moved from
	  plugins/fn-string/functions.c:search_pattern_to_regexp and turned into
	  a wrapper.
parent 6cf1b886
......@@ -84,7 +84,7 @@ Pending Patches
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.12) expression dialog
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
......
2002-12-06 Jody Goldberg <jody@gnome.org>
* src/regutf8.c (gnumeric_regcomp_XL) : moved from
plugins/fn-string/functions.c:search_pattern_to_regexp and turned into
a wrapper.
2002-12-05 Morten Welinder <terra@diku.dk>
* src/xml-io.c: Eliminate most char casts.
......
2002-12-06 Jody Goldberg <jody@gnome.org>
* src/regutf8.c (gnumeric_regcomp_XL) : moved from
plugins/fn-string/functions.c:search_pattern_to_regexp and turned into
a wrapper.
2002-12-05 Morten Welinder <terra@diku.dk>
* src/xml-io.c: Eliminate most char casts.
......
2002-12-06 Jody Goldberg <jody@gnome.org>
* src/regutf8.c (gnumeric_regcomp_XL) : moved from
plugins/fn-string/functions.c:search_pattern_to_regexp and turned into
a wrapper.
2002-12-05 Morten Welinder <terra@diku.dk>
* src/xml-io.c: Eliminate most char casts.
......
2002-12-06 Jody Goldberg <jody@gnome.org>
* ms-excel-read.c (excel_read_AUTOFILTER) : don't forget the unicode
header for biff8.
2002-12-03 Morten Welinder <terra@diku.dk>
* ms-excel-read.c (excel_print_unit_init_inch): Convert to
......
......@@ -4245,9 +4245,6 @@ read_DOPER (guint8 const *doper, gboolean is_equal,
g_return_val_if_fail (doper[1] > 0 && doper [1] <=6, NULL);
*op = ops [doper [1] - 1];
if (*op == GNM_FILTER_OP_EQUAL && !is_equal)
*op = GNM_FILTER_OP_REGEXP_MATCH;
return res;
}
......@@ -4284,18 +4281,21 @@ excel_read_AUTOFILTER (BiffQuery *q, ExcelSheet *esheet)
v0 = value_new_string_nocopy (
biff_get_text (data, len0, NULL));
data += len0;
if (esheet->container.ver >= MS_BIFF_V8)
data += 1; /* the header */
}
if (len1 > 0) {
if (len1 > 0)
v1 = value_new_string_nocopy (
biff_get_text (data, len1, NULL));
}
if (op1 == GNM_FILTER_UNUSED) {
cond = gnm_filter_condition_new_single (op0, v0);
if (v1 != NULL) value_release (v1); /* paranoia */
} else
} else {
/* NOTE : Docs are backwards */
cond = gnm_filter_condition_new_double (
op0, v0, (flags & 1) ? TRUE : FALSE, op1, v1);
op0, v0, (flags & 3) ? FALSE : TRUE, op1, v1);
}
}
gnm_filter_set_condition (filter,
......
2002-12-06 Jody Goldberg <jody@gnome.org>
* functions.c (gnumeric_search) : Use gnumeric_regcomp_XL.
(search_pattern_to_regexp) : move from here to the core and turn it
into gnumeric_regcomp_XL.
2002-11-15 Jody Goldberg <jody@gnome.org>
* Release 1.1.12
......
......@@ -1021,47 +1021,6 @@ static const char *help_search = {
"@SEEALSO=FIND")
};
static char *
search_pattern_to_regexp (const char *pattern)
{
GString *res = g_string_new ("");
while (*pattern) {
switch (*pattern) {
case '~':
pattern++;
if (*pattern == '*')
g_string_append (res, "\\*");
else
g_string_append_c (res, *pattern);
if (*pattern) pattern++;
break;
case '*':
g_string_append (res, ".*");
pattern++;
break;
case '?':
g_string_append_c (res, '.');
pattern++;
break;
case '.': case '[': case '\\':
case '^': case '$':
g_string_append_c (res, '\\');
g_string_append_c (res, *pattern++);
break;
default:
g_string_append_unichar (res, g_utf8_get_char (pattern));
pattern = g_utf8_next_char (pattern);
}
}
return g_string_free (res, FALSE);
}
static Value *
gnumeric_search (FunctionEvalInfo *ei, Value **argv)
{
......@@ -1069,7 +1028,6 @@ gnumeric_search (FunctionEvalInfo *ei, Value **argv)
const char *haystack = value_peek_string (argv[1]);
int start = argv[2] ? value_get_as_int (argv[2]) : 1;
const char *hay2;
char *needle_regexp;
gnumeric_regex_t r;
regmatch_t rm;
Value *res = NULL;
......@@ -1084,29 +1042,22 @@ gnumeric_search (FunctionEvalInfo *ei, Value **argv)
hay2 = g_utf8_next_char (hay2);
}
needle_regexp = search_pattern_to_regexp (needle);
if (gnumeric_regcomp (&r, needle_regexp, REG_ICASE) !=
REG_OK) {
g_assert_not_reached ();
goto out;
}
switch (gnumeric_regexec (&r, hay2, 1, &rm, 0)) {
case REG_NOMATCH:
break;
case REG_OK:
res = value_new_int (1 + start + rm.rm_so);
break;
default:
g_assert_not_reached ();
break;
if (gnumeric_regcomp_XL (&r, needle, REG_ICASE) == REG_OK) {
switch (gnumeric_regexec (&r, hay2, 1, &rm, 0)) {
case REG_NOMATCH: break;
case REG_OK:
res = value_new_int (1 + start + rm.rm_so);
break;
default:
g_warning ("Unexpected regexec result");
}
gnumeric_regfree (&r);
} else {
g_warning ("Unexpected regcomp result");
}
out:
if (!res) res = value_new_error (ei->pos, gnumeric_err_VALUE);
g_free (needle_regexp);
gnumeric_regfree (&r);
if (res == NULL)
res = value_new_error (ei->pos, gnumeric_err_VALUE);
return res;
}
......
2002-12-06 Jody Goldberg <jody@gnome.org>
* dialog-autofilter.c (init_operator) : new.
(dialog_auto_filter) : init the operators.
2002-12-05 Jody Goldberg <jody@gnome.org>
* dialog-autofilter.c (cb_top10_type_changed) : tweak the bounds as
......
......@@ -78,7 +78,7 @@
<property name="column_spacing">0</property>
<child>
<widget class="GtkOptionMenu" id="optionmenu3">
<widget class="GtkOptionMenu" id="op0">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="history">0</property>
......@@ -91,7 +91,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes"> </property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_unused_activate" last_modification_time="Wed, 04 Dec 2002 16:33:53 GMT"/>
</widget>
</child>
......@@ -100,7 +99,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">equals</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_equals1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -109,7 +107,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">does not equal</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_does_not_equal1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -118,7 +115,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">is greater than</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_is_greater_than1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -127,7 +123,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">is greater than or equal to</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_is_greater_than_or_equal_to1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -136,7 +131,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">is less than</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_is_less_than1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -145,7 +139,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">is less than or equal to</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_is_less_than_or_equal_to1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -154,7 +147,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">begins with</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_begins_with1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -163,7 +155,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">does not begin with</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_does_not_begin_with1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -172,7 +163,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">ends with</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_ends_with1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -181,7 +171,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">does not end with</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_does_not_end_with1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -190,7 +179,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">contains</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_contains1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -199,7 +187,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">does not contain</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_does_not_contain1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
</widget>
......@@ -216,7 +203,7 @@
</child>
<child>
<widget class="GtkOptionMenu" id="optionmenu4">
<widget class="GtkOptionMenu" id="op1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="history">0</property>
......@@ -229,7 +216,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes"> </property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_unused_activate" last_modification_time="Wed, 04 Dec 2002 16:33:53 GMT"/>
</widget>
</child>
......@@ -238,7 +224,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">equals</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_equals1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -247,7 +232,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">does not equal</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_does_not_equal1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -256,7 +240,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">is greater than</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_is_greater_than1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -265,7 +248,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">is greater than or equal to</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_is_greater_than_or_equal_to1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -274,7 +256,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">is less than</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_is_less_than1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -283,7 +264,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">is less than or equal to</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_is_less_than_or_equal_to1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -292,7 +272,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">begins with</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_begins_with1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -301,7 +280,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">does not begin with</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_does_not_begin_with1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -310,7 +288,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">ends with</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_ends_with1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -319,7 +296,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">does not end with</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_does_not_end_with1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -328,7 +304,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">contains</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_contains1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
......@@ -337,7 +312,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">does not contain</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_does_not_contain1_activate" last_modification_time="Wed, 04 Dec 2002 16:32:58 GMT"/>
</widget>
</child>
</widget>
......@@ -384,7 +358,7 @@
<property name="spacing">0</property>
<child>
<widget class="GtkRadioButton" id="radiobutton1">
<widget class="GtkRadioButton" id="and_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_And</property>
......@@ -402,7 +376,7 @@
</child>
<child>
<widget class="GtkRadioButton" id="radiobutton2">
<widget class="GtkRadioButton" id="or_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_Or</property>
......@@ -411,7 +385,7 @@
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
<property name="group">radiobutton1</property>
<property name="group">and_button</property>
</widget>
<packing>
<property name="padding">10</property>
......@@ -421,14 +395,56 @@
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
<property name="left_attach">0</property>
<property name="right_attach">3</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="y_padding">7</property>
<property name="x_options">fill</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="value0">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="value1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
......
......@@ -29,8 +29,7 @@
#include <workbook.h>
#include <workbook-edit.h>
#include <sheet.h>
#include <sheet-view.h>
#include <workbook-cmd-format.h>
#include <value.h>
#include <sheet-filter.h>
#include <glade/glade.h>
......@@ -68,6 +67,12 @@ 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));
} else {
int bottom, percentage, count;
......@@ -109,6 +114,44 @@ cb_top10_type_changed (GtkOptionMenu *menu,
(gtk_option_menu_get_history (menu) > 0) ? 100. : 500.);
}
static void
init_operator (AutoFilterState *state, GnmFilterOp op, Value const *v,
char const *op_widget, char const *val_widget)
{
GtkWidget *w = glade_xml_get_widget (state->gui, op_widget);
int i;
switch (op) {
case GNM_FILTER_OP_EQUAL: i = 1; break;
case GNM_FILTER_OP_GT: i = 3; break;
case GNM_FILTER_OP_LT: i = 5; break;
case GNM_FILTER_OP_GTE: i = 4; break;
case GNM_FILTER_OP_LTE: i = 6; break;
case GNM_FILTER_OP_NOT_EQUAL: i = 2; break;
default :
return;
};
if (v != NULL && v->type == VALUE_STRING && (i == 1 || i == 2)) {
char const *str = v->v_str.val->str;
unsigned const len = strlen (str);
/* there needs to be at least 1 letter */
gboolean starts = (len > 1 && str[0] == '*');
gboolean ends = (len > 1 && str[len-1] == '*' && str[len-2] != '~');
if (starts)
i += (ends ? 10 : 8);
else if (ends)
i += 6;
}
gtk_option_menu_set_history (GTK_OPTION_MENU (w), i);
if (v != NULL) {
w = glade_xml_get_widget (state->gui, val_widget);
gtk_entry_set_text (GTK_ENTRY (w), value_peek_string (v));
}
}
void
dialog_auto_filter (WorkbookControlGUI *wbcg,
GnmFilter *filter, int field,
......@@ -144,6 +187,14 @@ dialog_auto_filter (WorkbookControlGUI *wbcg,
if (cond != NULL) {
GnmFilterOp const op = cond->op[0];
if (is_expr && 0 == (op & GNM_FILTER_OP_TYPE_MASK)) {
init_operator (state, cond->op[0],
cond->value[0], "op0", "value0");
if (cond->op[1] != GNM_FILTER_UNUSED)
init_operator (state, cond->op[1],
cond->value[1], "op1", "value1");
w = glade_xml_get_widget (state->gui,
cond->is_and ? "and_button" : "or_button");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE);
} else if (!is_expr &&
GNM_FILTER_OP_TOP_N == (op & GNM_FILTER_OP_TYPE_MASK)) {
w = glade_xml_get_widget (state->gui, "top_vs_bottom_option_menu");
......
......@@ -461,3 +461,47 @@ main (int argc, char **argv)
#endif /* HAVE_UTF8_REGEXP */
int
gnumeric_regcomp_XL (gnumeric_regex_t *preg, char const *pattern, int cflags)
{
GString *res = g_string_new ("");
int retval;
while (*pattern) {
switch (*pattern) {
case '~':
pattern++;
if (*pattern == '*')
g_string_append (res, "\\*");
else
g_string_append_c (res, *pattern);
if (*pattern) pattern++;
break;
case '*':
g_string_append (res, ".*");
pattern++;
break;
case '?':
g_string_append_c (res, '.');
pattern++;
break;
case '.': case '[': case '\\':
case '^': case '$':
g_string_append_c (res, '\\');
g_string_append_c (res, *pattern++);
break;
default:
g_string_append_unichar (res, g_utf8_get_char (pattern));
pattern = g_utf8_next_char (pattern);
}
}
retval = gnumeric_regcomp (preg, res->str, cflags);
g_string_free (res, TRUE);
return retval;
}
......@@ -53,13 +53,15 @@ typedef struct {
size_t *parens;
} gnumeric_regex_t;
int gnumeric_regcomp (gnumeric_regex_t *preg, const char *pattern, int cflags);
int gnumeric_regexec (const gnumeric_regex_t *preg, const char *string,
int gnumeric_regcomp (gnumeric_regex_t *preg, char const *pattern, int cflags);
int gnumeric_regexec (gnumeric_regex_t const *preg, char const *string,
size_t nmatch, regmatch_t pmatch[], int eflags);
size_t gnumeric_regerror (int errcode, const gnumeric_regex_t *preg,
size_t gnumeric_regerror (int errcode, gnumeric_regex_t const *preg,
char *errbuf, size_t errbuf_size);
void gnumeric_regfree (gnumeric_regex_t *preg);
#endif
int gnumeric_regcomp_XL (gnumeric_regex_t *preg, char const *pattern, int cflags);
#endif
......@@ -35,6 +35,7 @@
#include "str.h"
#include "number-match.h"
#include "dialogs.h"
#include "regutf8.h"
#include <libfoocanvas/foo-canvas-widget.h>
#include <gtk/gtk.h>
......@@ -970,3 +971,18 @@ gnm_filter_contains_row (GnmFilter const *filter, int row)
return (filter->r.start.row <= row && row <= filter->r.end.row);
}
#if 0
if (gnumeric_regcomp_XL (&r, needle, REG_ICASE) == REG_OK) {
switch (gnumeric_regexec (&r, hay2, 1, &rm, 0)) {
case REG_NOMATCH: break;
case REG_OK:
res = value_new_int (1 + start + rm.rm_so);
break;
default:
g_warning ("Unexpected regexec result");
}
gnumeric_regfree (&r);
} else {
g_warning ("Unexpected regcomp result");
}
#endif
......@@ -16,8 +16,6 @@ typedef enum {
GNM_FILTER_OP_LTE = GNM_EXPR_OP_LTE,
GNM_FILTER_OP_NOT_EQUAL = GNM_EXPR_OP_NOT_EQUAL,
GNM_FILTER_OP_REGEXP_MATCH = 0x10 | GNM_EXPR_OP_EQUAL,
GNM_FILTER_OP_REGEXP_NOT_MATCH = 0x10 | GNM_EXPR_OP_NOT_EQUAL,
GNM_FILTER_OP_BLANKS = 0x20,
GNM_FILTER_OP_NON_BLANKS = 0x21,
GNM_FILTER_OP_TOP_N = 0x30,
......
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