~ubuntu-branches/ubuntu/feisty/gnumeric/feisty

« back to all changes in this revision

Viewing changes to src/sheet-filter.c

  • Committer: Bazaar Package Importer
  • Author(s): Gauvain Pocentek
  • Date: 2006-12-06 13:55:23 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20061206135523-6bh02cebuk0hduva
Tags: 1.7.5-1ubuntu1
* Merge with debian experimental:
  - debian/control, debian/*-gtk-*, debian/rules,
    debian/shlibs.local: Xubuntu changes for
    gtk/gnome multibuild.
  - run intltool-update in po*
  - Build Depend on intltool

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
2
 
3
3
/*
4
 
 * filter.c: support for filters
 
4
 * sheet-filter.c: support for 'auto-filters'
5
5
 *
6
6
 * Copyright (C) 2002-2006 Jody Goldberg (jody@gnome.org)
7
7
 *
21
21
 */
22
22
#include <gnumeric-config.h>
23
23
#include "sheet-filter.h"
 
24
#include "sheet-filter-combo.h"
24
25
 
25
26
#include "workbook.h"
26
27
#include "sheet.h"
28
29
#include "cell.h"
29
30
#include "expr.h"
30
31
#include "value.h"
31
 
#include "sheet-control-gui.h"
32
 
#include "sheet-object-impl.h"
33
 
#include "gnumeric-pane.h"
34
 
#include "gnumeric-canvas.h"
35
 
#include "dependent.h"
 
32
#include "gnm-format.h"
36
33
#include "ranges.h"
37
34
#include "str.h"
38
35
#include "number-match.h"
39
 
#include "dialogs.h"
40
 
#include "style-color.h"
41
36
#include "gutils.h"
42
 
#include "gnm-format.h"
43
 
 
44
 
#include <goffice/utils/regutf8.h>
45
 
#include <goffice/cut-n-paste/foocanvas/foo-canvas-widget.h>
46
 
#include <gtk/gtk.h>
47
 
#include <gdk/gdkevents.h>
48
 
#include <gdk/gdkkeysyms.h>
 
37
#include "sheet-object.h"
 
38
#include "gnm-filter-combo-foo-view.h"
 
39
#include "gnm-cell-combo-foo-view.h"
49
40
#include <gsf/gsf-impl-utils.h>
 
41
 
50
42
#include <glib/gi18n-lib.h>
 
43
#include <stdlib.h>
51
44
#include <string.h>
52
 
#include <stdlib.h>
53
 
 
54
 
typedef struct {
55
 
        SheetObject parent;
56
 
 
57
 
        GnmFilterCondition *cond;
58
 
        GnmFilter          *filter;
59
 
} GnmFilterField;
60
 
 
61
 
typedef struct {
62
 
        SheetObjectClass s_object_class;
63
 
} GnmFilterFieldClass;
64
 
 
65
 
#define FILTER_FIELD_TYPE     (filter_field_get_type ())
66
 
#define FILTER_FIELD(obj)     (G_TYPE_CHECK_INSTANCE_CAST((obj), FILTER_FIELD_TYPE, GnmFilterField))
67
 
 
68
 
#define VIEW_ITEM_ID    "view-item"
69
 
#define ARROW_ID        "arrow"
70
 
#define FIELD_ID        "field"
71
 
#define WBCG_ID         "wbcg"
72
 
 
73
 
static GType filter_field_get_type (void);
74
 
 
75
45
 
76
46
GnmFilterCondition *
77
47
gnm_filter_condition_new_single (GnmFilterOp op, GnmValue *v)
103
73
        return res;
104
74
}
105
75
 
 
76
GnmFilterCondition *
 
77
gnm_filter_condition_dup (GnmFilterCondition const *src)
 
78
{
 
79
        GnmFilterCondition *dst;
 
80
 
 
81
        if (src == NULL)
 
82
                return NULL;
 
83
 
 
84
        dst = g_new0 (GnmFilterCondition, 1);
 
85
        dst->op[0]    = src->op[0];
 
86
        dst->op[1]    = src->op[1];
 
87
        dst->is_and   = src->is_and;
 
88
        dst->count    = src->count;
 
89
        dst->value[0] = value_dup (src->value[0]);
 
90
        dst->value[1] = value_dup (src->value[1]);
 
91
        return dst;
 
92
}
 
93
 
106
94
void
107
95
gnm_filter_condition_unref (GnmFilterCondition *cond)
108
96
{
113
101
                value_release (cond->value[1]);
114
102
}
115
103
 
116
 
/**********************************************************************************/
117
 
 
118
 
static int
119
 
filter_field_index (GnmFilterField const *field)
120
 
{
121
 
        return field->parent.anchor.cell_bound.start.col -
122
 
                field->filter->r.start.col;
123
 
}
124
 
 
125
 
static void
126
 
filter_field_finalize (GObject *object)
127
 
{
128
 
        GnmFilterField *field = FILTER_FIELD (object);
129
 
        GObjectClass *parent;
130
 
 
131
 
        g_return_if_fail (field != NULL);
132
 
 
133
 
        if (field->cond != NULL) {
134
 
                gnm_filter_condition_unref (field->cond);
135
 
                field->cond = NULL;
136
 
        }
137
 
 
138
 
        parent = g_type_class_peek (SHEET_OBJECT_TYPE);
139
 
        parent->finalize (object);
140
 
}
141
 
 
142
 
/* Cut and paste from gtkwindow.c */
143
 
static void
144
 
do_focus_change (GtkWidget *widget, gboolean in)
145
 
{
146
 
        GdkEventFocus fevent;
147
 
 
148
 
        g_object_ref (widget);
149
 
 
150
 
        if (in)
151
 
                GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
152
 
        else
153
 
                GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
154
 
 
155
 
        fevent.type = GDK_FOCUS_CHANGE;
156
 
        fevent.window = widget->window;
157
 
        fevent.in = in;
158
 
 
159
 
        gtk_widget_event (widget, (GdkEvent *)&fevent);
160
 
 
161
 
        g_object_notify (G_OBJECT (widget), "has-focus");
162
 
 
163
 
        g_object_unref (widget);
164
 
}
165
 
 
166
 
static void
167
 
filter_popup_destroy (GtkWidget *popup, GtkWidget *list)
168
 
{
169
 
        do_focus_change (list, FALSE);
170
 
        gtk_widget_destroy (popup);
171
 
}
172
 
 
173
 
static gint
174
 
cb_filter_key_press (GtkWidget *popup, GdkEventKey *event, GtkWidget *list)
175
 
{
176
 
        if (event->keyval != GDK_Escape)
177
 
                return FALSE;
178
 
        filter_popup_destroy (popup, list);
179
 
        return TRUE;
180
 
}
181
 
 
182
 
static gint
183
 
cb_filter_button_press (GtkWidget *popup, GdkEventButton *event,
184
 
                        GtkWidget *list)
185
 
{
186
 
        /* A press outside the popup cancels */
187
 
        if (event->window != popup->window) {
188
 
                filter_popup_destroy (popup, list);
189
 
                return TRUE;
190
 
        }
191
 
        return FALSE;
192
 
}
193
 
 
194
 
static gint
195
 
cb_filter_button_release (GtkWidget *popup, GdkEventButton *event,
196
 
                          GtkTreeView *list)
197
 
{
198
 
        GtkTreeIter  iter;
199
 
        GnmFilterField *field;
200
 
        GnmFilterCondition *cond = NULL;
201
 
        WorkbookControlGUI *wbcg;
202
 
        GtkWidget *event_widget = gtk_get_event_widget ((GdkEvent *) event);
203
 
        int field_num;
204
 
 
205
 
        /* A release inside list accepts */
206
 
        if (event_widget != GTK_WIDGET (list))
207
 
                return FALSE;
208
 
 
209
 
        field = g_object_get_data (G_OBJECT (list), FIELD_ID);
210
 
        wbcg  = g_object_get_data (G_OBJECT (list), WBCG_ID);
211
 
        if (field != NULL &&
212
 
            gtk_tree_selection_get_selected (gtk_tree_view_get_selection (list),
213
 
                                             NULL, &iter)) {
214
 
                char    *strval;
215
 
                int      type;
216
 
                gboolean set_condition = TRUE;
217
 
 
218
 
                gtk_tree_model_get (gtk_tree_view_get_model (list), &iter,
219
 
                                    1, &strval, 2, &type,
220
 
                                    -1);
221
 
 
222
 
                field_num = filter_field_index (field);
223
 
                switch (type) {
224
 
                case  0:
225
 
                        cond = gnm_filter_condition_new_single (
226
 
                                GNM_FILTER_OP_EQUAL,
227
 
                                value_new_string_nocopy (strval));
228
 
                        strval = NULL;                  
229
 
                        break;
230
 
                case  1: /* unfilter */
231
 
                        cond = NULL;
232
 
                        break;
233
 
                case  2: /* Custom */
234
 
                        set_condition = FALSE;
235
 
                        dialog_auto_filter (wbcg, field->filter, field_num,
236
 
                                            TRUE, field->cond);
237
 
                        break;
238
 
                case  3:
239
 
                        cond = gnm_filter_condition_new_single (
240
 
                                GNM_FILTER_OP_BLANKS, NULL);
241
 
                        break;
242
 
                case  4:
243
 
                        cond = gnm_filter_condition_new_single (
244
 
                                GNM_FILTER_OP_NON_BLANKS, NULL);
245
 
                        break;
246
 
                case 10: /* Top 10 */
247
 
                        set_condition = FALSE;
248
 
                        dialog_auto_filter (wbcg, field->filter, field_num,
249
 
                                            FALSE, field->cond);
250
 
                        break;
251
 
                default:
252
 
                        set_condition = FALSE;
253
 
                        g_warning ("Unknown type %d", type);
254
 
                }
255
 
 
256
 
                g_free (strval);
257
 
 
258
 
                if (set_condition) {
259
 
                        gnm_filter_set_condition (field->filter, field_num,
260
 
                                                  cond, TRUE);
261
 
                        sheet_update (field->filter->sheet);
262
 
                }
263
 
        }
264
 
        filter_popup_destroy (popup, GTK_WIDGET (list));
265
 
        return TRUE;
266
 
}
267
 
 
268
 
static gboolean
269
 
cb_filter_motion_notify_event (GtkWidget *widget, GdkEventMotion *event,
270
 
                               GtkTreeView *list)
271
 
{
272
 
        GtkTreePath *path;
273
 
        if (event->x >= 0 && event->y >= 0 &&
274
 
            event->x < widget->allocation.width &&
275
 
            event->y < widget->allocation.height &&
276
 
            gtk_tree_view_get_path_at_pos (list, event->x, event->y,
277
 
                                           &path, NULL, NULL, NULL)) {
278
 
                gtk_tree_selection_select_path (gtk_tree_view_get_selection (list), path);
279
 
                gtk_tree_path_free (path);
280
 
        }
281
 
        return TRUE;
282
 
}
283
 
 
284
 
typedef struct {
285
 
        gboolean has_blank;
286
 
        GHashTable *hash;
287
 
        GODateConventions const *date_conv;
288
 
} UniqueCollection;
289
 
 
290
 
static GnmValue *
291
 
cb_collect_unique (GnmCellIter const *iter, UniqueCollection *uc)
292
 
{
293
 
        if (cell_is_blank (iter->cell))
294
 
                uc->has_blank = TRUE;
295
 
        else {
296
 
                GOFormat const *format = cell_get_format (iter->cell);                  
297
 
                GnmValue const *v = iter->cell->value;
298
 
                char *str = format_value (format, v, NULL, -1, uc->date_conv);
299
 
                g_hash_table_replace (uc->hash, str, iter->cell);
300
 
        }
301
 
 
302
 
        return NULL;
303
 
}
304
 
 
305
 
static void
306
 
cb_hash_domain (GnmValue *key, gpointer value, gpointer accum)
307
 
{
308
 
        g_ptr_array_add (accum, key);
309
 
}
310
 
 
311
 
static int
312
 
order_alphabetically (void const *ptr_a, void const *ptr_b)
313
 
{
314
 
        char const * const *a = ptr_a;
315
 
        char const * const *b = ptr_b;
316
 
        return strcmp (*a, *b);
317
 
}
318
 
 
319
 
static GtkListStore *
320
 
collect_unique_elements (GnmFilterField *field,
321
 
                         GtkTreePath **clip, GtkTreePath **select)
322
 
{
323
 
        UniqueCollection uc;
324
 
        GtkTreeIter      iter;
325
 
        GtkListStore *model;
326
 
        GPtrArray    *sorted = g_ptr_array_new ();
327
 
        unsigned i;
328
 
        gboolean is_custom = FALSE;
329
 
        GnmRange         r = field->filter->r;
330
 
        GnmValue const *check = NULL;
331
 
        Sheet *sheet = field->filter->sheet;
332
 
 
333
 
        if (field->cond != NULL &&
334
 
            field->cond->op[0] == GNM_FILTER_OP_EQUAL &&
335
 
            field->cond->op[1] == GNM_FILTER_UNUSED) {
336
 
                check = field->cond->value[0];
337
 
        }
338
 
 
339
 
        model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
340
 
 
341
 
        gtk_list_store_append (model, &iter);
342
 
        gtk_list_store_set (model, &iter, 0, _("(All)"),           1, NULL, 2, 1, -1);
343
 
        if (field->cond == NULL || field->cond->op[0] == GNM_FILTER_UNUSED)
344
 
                *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
345
 
 
346
 
        gtk_list_store_append (model, &iter);
347
 
        gtk_list_store_set (model, &iter, 0, _("(Top 10...)"),     1, NULL, 2, 10,-1);
348
 
        if (field->cond != NULL &&
349
 
            (GNM_FILTER_OP_TYPE_MASK & field->cond->op[0]) == GNM_FILTER_OP_TOP_N)
350
 
                *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
351
 
 
352
 
        /* default to this we can easily revamp later */
353
 
        gtk_list_store_append (model, &iter);
354
 
        gtk_list_store_set (model, &iter, 0, _("(Custom...)"),     1, NULL, 2, 2, -1);
355
 
        if (*select == NULL) {
356
 
                is_custom = TRUE;
357
 
                *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
358
 
        }
359
 
 
360
 
        r.start.row++;
361
 
        /* r.end.row =  XL actually extend to the first non-empty element in the list */
362
 
        r.end.col = r.start.col += filter_field_index (field);
363
 
        uc.has_blank = FALSE;
364
 
        uc.hash = g_hash_table_new_full (g_str_hash, g_str_equal,
365
 
                                         (GDestroyNotify)g_free,
366
 
                                         NULL);
367
 
        uc.date_conv = workbook_date_conv (sheet->workbook);
368
 
 
369
 
        sheet_foreach_cell_in_range (sheet,
370
 
                CELL_ITER_ALL,
371
 
                r.start.col, r.start.row, r.end.col, r.end.row,
372
 
                (CellIterFunc)&cb_collect_unique, &uc);
373
 
 
374
 
        g_hash_table_foreach (uc.hash, (GHFunc)cb_hash_domain, sorted);
375
 
        qsort (&g_ptr_array_index (sorted, 0),
376
 
               sorted->len, sizeof (char *),
377
 
               order_alphabetically);
378
 
        for (i = 0; i < sorted->len ; i++) {
379
 
                char const *str = g_ptr_array_index (sorted, i);
380
 
                char *label = NULL;
381
 
                gsize len = g_utf8_strlen (str, -1);
382
 
                unsigned const max = 50;
383
 
 
384
 
                if (len > max + 3) {
385
 
                        label = g_strdup (str);
386
 
                        strcpy (g_utf8_offset_to_pointer (label, max), "...");
387
 
                }
388
 
 
389
 
                gtk_list_store_append (model, &iter);
390
 
                gtk_list_store_set (model, &iter,
391
 
                                    0, label ? label : str, /* Menu text */
392
 
                                    1, str, /* Actual string selected on.  */
393
 
                                    2, 0,
394
 
                                    -1);
395
 
                g_free (label);
396
 
                if (i == 10)
397
 
                        *clip = gtk_tree_model_get_path (GTK_TREE_MODEL (model),
398
 
                                                         &iter);
399
 
                if (check != NULL) {
400
 
                        if (strcmp (value_peek_string (check), str) == 0) {
401
 
                                gtk_tree_path_free (*select);
402
 
                                *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
403
 
                        }
404
 
                }
405
 
        }
406
 
 
407
 
        if (uc.has_blank) {
408
 
                gtk_list_store_append (model, &iter);
409
 
                gtk_list_store_set (model, &iter, 0, _("(Blanks...)"),     1, NULL, 2, 3, -1);
410
 
                if (field->cond != NULL &&
411
 
                    field->cond->op[0] == GNM_FILTER_OP_BLANKS)
412
 
                        *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
413
 
 
414
 
                gtk_list_store_append (model, &iter);
415
 
                gtk_list_store_set (model, &iter, 0, _("(Non Blanks...)"), 1, NULL, 2, 4, -1);
416
 
                if (field->cond != NULL &&
417
 
                    field->cond->op[0] == GNM_FILTER_OP_NON_BLANKS)
418
 
                        *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
419
 
        } else if (is_custom && field->cond != NULL &&
420
 
                   (GNM_FILTER_OP_TYPE_MASK & field->cond->op[0]) == GNM_FILTER_OP_BLANKS) {
421
 
                gtk_tree_path_free (*select);
422
 
                *select = NULL;
423
 
        }
424
 
 
425
 
        g_hash_table_destroy (uc.hash);
426
 
        g_ptr_array_free (sorted, TRUE);
427
 
 
428
 
        return model;
429
 
}
430
 
 
431
 
static void
432
 
cb_focus_changed (GtkWindow *toplevel)
433
 
{
434
 
#if 0
435
 
        g_warning (gtk_window_has_toplevel_focus (toplevel) ? "focus" : "no focus");
436
 
#endif
437
 
}
438
 
 
439
 
static void
440
 
cb_filter_button_pressed (GtkButton *button, FooCanvasItem *view)
441
 
{
442
 
        GnmPane         *pane = GNM_CANVAS (view->canvas)->pane;
443
 
        SheetControlGUI *scg = pane->gcanvas->simple.scg;
444
 
        SheetObject     *so = sheet_object_view_get_so (SHEET_OBJECT_VIEW (view));
445
 
        GnmFilterField  *field = FILTER_FIELD (so);
446
 
        GtkWidget *frame, *popup, *list, *container;
447
 
        int root_x, root_y;
448
 
        GtkListStore  *model;
449
 
        GtkTreeViewColumn *column;
450
 
        GtkTreePath       *clip = NULL, *select = NULL;
451
 
        GtkRequisition  req;
452
 
 
453
 
        popup = gtk_window_new (GTK_WINDOW_POPUP);
454
 
        model = collect_unique_elements (field, &clip, &select);
455
 
        column = gtk_tree_view_column_new_with_attributes ("ID",
456
 
                        gtk_cell_renderer_text_new (), "text", 0,
457
 
                        NULL);
458
 
        list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
459
 
        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list), FALSE);
460
 
        gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
461
 
        gtk_widget_size_request (GTK_WIDGET (list), &req);
462
 
        g_object_set_data (G_OBJECT (list), FIELD_ID, field);
463
 
        g_object_set_data (G_OBJECT (list), WBCG_ID, scg_get_wbcg (scg));
464
 
        g_signal_connect (G_OBJECT (wbcg_toplevel (scg_get_wbcg (scg))),
465
 
                "notify::has-toplevel-focus",
466
 
                G_CALLBACK (cb_focus_changed), list);
467
 
 
468
 
        frame = gtk_frame_new (NULL);
469
 
        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
470
 
 
471
 
#if 0
472
 
        range_dump (&so->anchor.cell_bound, "");
473
 
        fprintf (stderr, " : so = %p, view = %p\n", so, view);
474
 
#endif
475
 
        if (clip != NULL) {
476
 
                GdkRectangle  rect;
477
 
                GtkWidget *sw = gtk_scrolled_window_new (
478
 
                        gtk_tree_view_get_hadjustment (GTK_TREE_VIEW (list)),
479
 
                        gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (list)));
480
 
                gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
481
 
                                                GTK_POLICY_AUTOMATIC,
482
 
                                                GTK_POLICY_ALWAYS);
483
 
                gtk_tree_view_get_background_area (GTK_TREE_VIEW (list),
484
 
                                                   clip, NULL, &rect);
485
 
                gtk_tree_path_free (clip);
486
 
 
487
 
                gtk_widget_set_size_request (list, req.width, rect.y);
488
 
                gtk_container_add (GTK_CONTAINER (sw), list);
489
 
                container = sw;
490
 
        } else
491
 
                container = list;
492
 
 
493
 
        gtk_container_add (GTK_CONTAINER (frame), container);
494
 
 
495
 
        /* do the popup */
496
 
        gtk_window_set_decorated (GTK_WINDOW (popup), FALSE);
497
 
        gdk_window_get_origin (GTK_WIDGET (pane->gcanvas)->window,
498
 
                &root_x, &root_y);
499
 
        gtk_window_move (GTK_WINDOW (popup),
500
 
                root_x + scg_colrow_distance_get (scg, TRUE,
501
 
                        pane->gcanvas->first.col,
502
 
                        field->parent.anchor.cell_bound.start.col + 1) - req.width,
503
 
                root_y + scg_colrow_distance_get (scg, FALSE,
504
 
                        pane->gcanvas->first.row,
505
 
                        field->filter->r.start.row + 1));
506
 
 
507
 
        gtk_container_add (GTK_CONTAINER (popup), frame);
508
 
 
509
 
        g_signal_connect (popup,
510
 
                "key_press_event",
511
 
                G_CALLBACK (cb_filter_key_press), list);
512
 
        g_signal_connect (popup,
513
 
                "button_press_event",
514
 
                G_CALLBACK (cb_filter_button_press), list);
515
 
        g_signal_connect (popup,
516
 
                "button_release_event",
517
 
                G_CALLBACK (cb_filter_button_release), list);
518
 
        g_signal_connect (list,
519
 
                "motion_notify_event",
520
 
                G_CALLBACK (cb_filter_motion_notify_event), list);
521
 
 
522
 
        gtk_widget_show_all (popup);
523
 
 
524
 
        /* after we show the window setup the selection (showing the list
525
 
         * clears the selection) */
526
 
        if (select != NULL) {
527
 
                gtk_tree_selection_select_path (
528
 
                        gtk_tree_view_get_selection (GTK_TREE_VIEW (list)),
529
 
                        select);
530
 
                gtk_tree_path_free (select);
531
 
        }
532
 
 
533
 
        gtk_widget_grab_focus (GTK_WIDGET (list));
534
 
        do_focus_change (GTK_WIDGET (list), TRUE);
535
 
 
536
 
        gtk_grab_add (popup);
537
 
        gdk_pointer_grab (popup->window, TRUE,
538
 
                GDK_BUTTON_PRESS_MASK |
539
 
                GDK_BUTTON_RELEASE_MASK |
540
 
                GDK_POINTER_MOTION_MASK,
541
 
                NULL, NULL, GDK_CURRENT_TIME);
542
 
}
543
 
 
544
 
static void
545
 
filter_field_arrow_format (GnmFilterField *field, GtkWidget *arrow)
546
 
{
547
 
        gtk_arrow_set (GTK_ARROW (arrow),
548
 
                field->cond != NULL ? GTK_ARROW_RIGHT : GTK_ARROW_DOWN,
549
 
                GTK_SHADOW_IN);
550
 
        gtk_widget_modify_fg (arrow, GTK_STATE_NORMAL,
551
 
                field->cond != NULL ? &gs_yellow : &gs_black);
552
 
}
553
 
 
554
 
static void
555
 
filter_view_destroy (SheetObjectView *sov)
556
 
{
557
 
        gtk_object_destroy (GTK_OBJECT (sov));
558
 
}
559
 
static void
560
 
filter_view_set_bounds (SheetObjectView *sov, double const *coords, gboolean visible)
561
 
{
562
 
        FooCanvasItem *view = FOO_CANVAS_ITEM (sov);
563
 
 
564
 
        if (visible) {
565
 
                double h, x;
566
 
                /* clip vertically */
567
 
                h = (coords[3] - coords[1]);
568
 
                if (h > 20.)
569
 
                        h = 20.;
570
 
 
571
 
                /* maintain squareness horzontally */
572
 
                x = coords[2] - h;
573
 
                if (x < coords[0])
574
 
                        x = coords[0];
575
 
 
576
 
                /* NOTE : far point is EXCLUDED so we add 1 */
577
 
                foo_canvas_item_set (view,
578
 
                        "x",    x,
579
 
                        "y",    coords [3] - h,
580
 
                        "width",  coords [2] - x,
581
 
                        "height", h + 1.,
582
 
                        NULL);
583
 
 
584
 
                foo_canvas_item_show (view);
585
 
        } else
586
 
                foo_canvas_item_hide (view);
587
 
}
588
 
 
589
 
static void
590
 
filter_foo_view_init (SheetObjectViewIface *sov_iface)
591
 
{
592
 
        sov_iface->destroy      = filter_view_destroy;
593
 
        sov_iface->set_bounds   = filter_view_set_bounds;
594
 
}
595
 
typedef FooCanvasWidget         FilterFooView;
596
 
typedef FooCanvasWidgetClass    FilterFooViewClass;
597
 
static GSF_CLASS_FULL (FilterFooView, filter_foo_view,
598
 
        NULL, NULL, NULL, NULL,
599
 
        NULL, FOO_TYPE_CANVAS_WIDGET, 0,
600
 
        GSF_INTERFACE (filter_foo_view_init, SHEET_OBJECT_VIEW_TYPE))
601
 
 
602
 
static SheetObjectView *
603
 
filter_field_new_view (SheetObject *so, SheetObjectViewContainer *container)
604
 
{
605
 
        GnmCanvas *gcanvas = ((GnmPane *)container)->gcanvas;
606
 
        GtkWidget *arrow, *view_widget = gtk_button_new ();
607
 
        GnmFilterField *field = (GnmFilterField *) so;
608
 
        FooCanvasItem *view_item = foo_canvas_item_new (gcanvas->object_views,
609
 
                filter_foo_view_get_type (),
610
 
                "widget",       view_widget,
611
 
                "size_pixels",  FALSE,
612
 
                NULL);
613
 
 
614
 
        GTK_WIDGET_UNSET_FLAGS (view_widget, GTK_CAN_FOCUS);
615
 
        arrow = gtk_arrow_new (field->cond != NULL ? GTK_ARROW_RIGHT : GTK_ARROW_DOWN,
616
 
                               GTK_SHADOW_IN);
617
 
        filter_field_arrow_format (field, arrow);
618
 
        gtk_container_add (GTK_CONTAINER (view_widget), arrow);
619
 
 
620
 
        g_object_set_data (G_OBJECT (view_widget), VIEW_ITEM_ID, view_item);
621
 
        g_object_set_data (G_OBJECT (view_item), ARROW_ID, arrow);
622
 
        g_signal_connect (view_widget,
623
 
                "pressed",
624
 
                G_CALLBACK (cb_filter_button_pressed), view_item);
625
 
        gtk_widget_show_all (view_widget);
626
 
 
627
 
        return gnm_pane_object_register (so, view_item, FALSE);
628
 
}
629
 
 
630
 
static void
631
 
filter_field_init (SheetObject *so)
632
 
{
633
 
        /* keep the arrows from wandering with their cells */
634
 
        so->flags &= ~SHEET_OBJECT_MOVE_WITH_CELLS;
635
 
}
636
 
 
637
 
static void
638
 
filter_field_class_init (GObjectClass *object_class)
639
 
{
640
 
        SheetObjectClass *sheet_object_class = SHEET_OBJECT_CLASS (object_class);
641
 
 
642
 
        /* Object class method overrides */
643
 
        object_class->finalize = filter_field_finalize;
644
 
 
645
 
        /* SheetObject class method overrides */
646
 
        sheet_object_class->new_view      = filter_field_new_view;
647
 
        sheet_object_class->read_xml_dom  = NULL;
648
 
        sheet_object_class->write_xml_sax = NULL;
649
 
        sheet_object_class->print         = NULL;
650
 
        sheet_object_class->copy          = NULL;
651
 
}
652
 
 
653
 
GSF_CLASS (GnmFilterField, filter_field,
654
 
           filter_field_class_init, filter_field_init,
655
 
           SHEET_OBJECT_TYPE);
656
 
 
657
104
/*****************************************************************************/
658
105
 
659
106
typedef struct  {
660
107
        GnmFilterCondition const *cond;
661
108
        GnmValue                 *val[2];
662
109
        GORegexp                  regexp[2];
 
110
        Sheet                    *target_sheet; /* not necessarilly the src */
663
111
} FilterExpr;
664
112
 
665
113
static void
705
153
        GnmValDiff cmp;
706
154
 
707
155
        if (src == NULL) {
708
 
                GOFormat const *format = cell_get_format (cell);                        
 
156
                GOFormat const *format = gnm_cell_get_format (cell);                    
709
157
                GODateConventions const *date_conv =
710
158
                        workbook_date_conv (cell->base.sheet->workbook);
711
159
                char *str = format_value (format, target, NULL, -1, date_conv);
772
220
        }
773
221
 
774
222
 nope:
775
 
        colrow_set_visibility (iter->pp.sheet, FALSE, FALSE,
 
223
        colrow_set_visibility (fexpr->target_sheet, FALSE, FALSE,
776
224
                iter->pp.eval.row, iter->pp.eval.row);
777
225
        return NULL;
778
226
}
780
228
/*****************************************************************************/
781
229
 
782
230
static GnmValue *
783
 
cb_filter_non_blanks (GnmCellIter const *iter, G_GNUC_UNUSED gpointer user)
 
231
cb_filter_non_blanks (GnmCellIter const *iter, Sheet *target_sheet)
784
232
{
785
 
        if (cell_is_blank (iter->cell))
786
 
                colrow_set_visibility (iter->pp.sheet, FALSE, FALSE,
 
233
        if (gnm_cell_is_blank (iter->cell))
 
234
                colrow_set_visibility (target_sheet, FALSE, FALSE,
787
235
                        iter->pp.eval.row, iter->pp.eval.row);
788
236
        return NULL;
789
237
}
790
238
 
791
239
static GnmValue *
792
 
cb_filter_blanks (GnmCellIter const *iter, G_GNUC_UNUSED gpointer user)
 
240
cb_filter_blanks (GnmCellIter const *iter, Sheet *target_sheet)
793
241
{
794
 
        if (!cell_is_blank (iter->cell))
795
 
                colrow_set_visibility (iter->pp.sheet, FALSE, FALSE,
 
242
        if (!gnm_cell_is_blank (iter->cell))
 
243
                colrow_set_visibility (target_sheet, FALSE, FALSE,
796
244
                        iter->pp.eval.row, iter->pp.eval.row);
797
245
        return NULL;
798
246
}
804
252
        unsigned elements;
805
253
        gboolean find_max;
806
254
        GnmValue const **vals;
 
255
        Sheet   *target_sheet;
807
256
} FilterItems;
808
257
 
809
258
static GnmValue *
842
291
                        if (data->vals[i] == v)
843
292
                                return NULL;
844
293
        }
845
 
        colrow_set_visibility (iter->pp.sheet, FALSE, FALSE,
 
294
        colrow_set_visibility (data->target_sheet, FALSE, FALSE,
846
295
                iter->pp.eval.row, iter->pp.eval.row);
847
296
        return NULL;
848
297
}
850
299
/*****************************************************************************/
851
300
 
852
301
typedef struct {
853
 
        gboolean        initialized, find_max;
854
 
        gnm_float       low, high;
 
302
        gboolean         initialized, find_max;
 
303
        gnm_float        low, high;
 
304
        Sheet           *target_sheet;
855
305
} FilterPercentage;
856
306
 
857
307
static GnmValue *
887
337
                                return NULL;
888
338
                }
889
339
        }
890
 
        colrow_set_visibility (iter->pp.sheet, FALSE, FALSE,
 
340
        colrow_set_visibility (data->target_sheet, FALSE, FALSE,
891
341
                iter->pp.eval.row, iter->pp.eval.row);
892
342
        return NULL;
893
343
}
894
344
/*****************************************************************************/
895
345
 
896
 
static void
897
 
filter_field_apply (GnmFilterField *field)
 
346
/**
 
347
 * gnm_filter_combo_apply :
 
348
 * @fcombo : #GnmFilterCombo
 
349
 * @target_sheet : @Sheet
 
350
 *
 
351
 **/
 
352
void
 
353
gnm_filter_combo_apply (GnmFilterCombo *fcombo, Sheet *target_sheet)
898
354
{
899
 
        GnmFilter *filter = field->filter;
900
 
        int const col = field->parent.anchor.cell_bound.start.col;
 
355
        GnmFilter const *filter = fcombo->filter;
 
356
        GnmFilterCondition const *cond = fcombo->cond;
 
357
        int const col = sheet_object_get_range (SHEET_OBJECT (fcombo))->start.col;
901
358
        int const start_row = filter->r.start.row + 1;
902
359
        int const end_row = filter->r.end.row;
903
 
 
904
 
        if (start_row > end_row)
905
 
                return;
906
 
 
907
 
        if (field->cond == NULL ||
908
 
            field->cond->op[0] == GNM_FILTER_UNUSED)
909
 
                return;
910
 
        if (0x10 >= (field->cond->op[0] & GNM_FILTER_OP_TYPE_MASK)) {
 
360
        CellIterFlags iter_flags = CELL_ITER_IGNORE_HIDDEN;
 
361
 
 
362
        if (start_row > end_row ||
 
363
            cond == NULL ||
 
364
            cond->op[0] == GNM_FILTER_UNUSED)
 
365
                return;
 
366
 
 
367
        /* For the combo we filter a temporary sheet using the data from filter->sheet
 
368
         * and need to include everything from the source, because it has a
 
369
         * different set of conditions */
 
370
        if (target_sheet != filter->sheet)
 
371
                iter_flags = CELL_ITER_ALL;
 
372
 
 
373
        if (0x10 >= (cond->op[0] & GNM_FILTER_OP_TYPE_MASK)) {
911
374
                FilterExpr data;
912
 
                data.cond = field->cond;
913
 
                filter_expr_init (&data, 0, field->cond, filter);
914
 
                if (field->cond->op[1] != GNM_FILTER_UNUSED)
915
 
                        filter_expr_init (&data, 1, field->cond, field->filter);
 
375
                data.cond = cond;
 
376
                data.target_sheet = target_sheet;
 
377
                filter_expr_init (&data, 0, cond, filter);
 
378
                if (cond->op[1] != GNM_FILTER_UNUSED)
 
379
                        filter_expr_init (&data, 1, cond, filter);
916
380
 
917
381
                sheet_foreach_cell_in_range (filter->sheet,
918
 
                        CELL_ITER_IGNORE_HIDDEN,
 
382
                        (target_sheet == filter->sheet) ? CELL_ITER_IGNORE_HIDDEN : CELL_ITER_ALL,
919
383
                        col, start_row, col, end_row,
920
384
                        (CellIterFunc) cb_filter_expr, &data);
921
385
 
922
386
                filter_expr_release (&data, 0);
923
 
                if (field->cond->op[1] != GNM_FILTER_UNUSED)
 
387
                if (cond->op[1] != GNM_FILTER_UNUSED)
924
388
                        filter_expr_release (&data, 1);
925
 
        } else if (field->cond->op[0] == GNM_FILTER_OP_BLANKS)
926
 
                sheet_foreach_cell_in_range (filter->sheet,
927
 
                        CELL_ITER_IGNORE_HIDDEN,
928
 
                        col, start_row, col, end_row,
929
 
                        cb_filter_blanks, NULL);
930
 
        else if (field->cond->op[0] == GNM_FILTER_OP_NON_BLANKS)
931
 
                sheet_foreach_cell_in_range (filter->sheet,
932
 
                        CELL_ITER_IGNORE_HIDDEN,
933
 
                        col, start_row, col, end_row,
934
 
                        cb_filter_non_blanks, NULL);
935
 
        else if (0x30 == (field->cond->op[0] & GNM_FILTER_OP_TYPE_MASK)) {
936
 
                if (field->cond->op[0] & 0x2) { /* relative */
 
389
        } else if (cond->op[0] == GNM_FILTER_OP_BLANKS)
 
390
                sheet_foreach_cell_in_range (filter->sheet,
 
391
                        CELL_ITER_IGNORE_HIDDEN,
 
392
                        col, start_row, col, end_row,
 
393
                        (CellIterFunc) cb_filter_blanks, target_sheet);
 
394
        else if (cond->op[0] == GNM_FILTER_OP_NON_BLANKS)
 
395
                sheet_foreach_cell_in_range (filter->sheet,
 
396
                        CELL_ITER_IGNORE_HIDDEN,
 
397
                        col, start_row, col, end_row,
 
398
                        (CellIterFunc) cb_filter_non_blanks, target_sheet);
 
399
        else if (0x30 == (cond->op[0] & GNM_FILTER_OP_TYPE_MASK)) {
 
400
                if (cond->op[0] & 0x2) { /* relative */
937
401
                        FilterPercentage data;
938
402
                        gnm_float        offset;
939
403
 
940
 
                        data.find_max = (field->cond->op[0] & 0x1) ? FALSE : TRUE;
 
404
                        data.find_max = (cond->op[0] & 0x1) ? FALSE : TRUE;
941
405
                        data.initialized = FALSE;
942
406
                        sheet_foreach_cell_in_range (filter->sheet,
943
407
                                CELL_ITER_IGNORE_HIDDEN | CELL_ITER_IGNORE_BLANK,
944
408
                                col, start_row, col, end_row,
945
409
                                (CellIterFunc) cb_filter_find_percentage, &data);
946
 
                        offset = (data.high - data.low) * field->cond->count / 100.;
 
410
                        offset = (data.high - data.low) * cond->count / 100.;
947
411
                        data.high -= offset;
948
412
                        data.low  += offset;
 
413
                        data.target_sheet = target_sheet;
949
414
                        sheet_foreach_cell_in_range (filter->sheet,
950
415
                                CELL_ITER_IGNORE_HIDDEN,
951
416
                                col, start_row, col, end_row,
952
417
                                (CellIterFunc) cb_hide_unwanted_percentage, &data);
953
418
                } else { /* absolute */
954
419
                        FilterItems data;
955
 
                        data.find_max = (field->cond->op[0] & 0x1) ? FALSE : TRUE;
 
420
                        data.find_max = (cond->op[0] & 0x1) ? FALSE : TRUE;
956
421
                        data.elements    = 0;
957
 
                        data.count  = field->cond->count;
 
422
                        data.count  = cond->count;
958
423
                        data.vals   = g_alloca (sizeof (GnmValue *) * data.count);
959
424
                        sheet_foreach_cell_in_range (filter->sheet,
960
425
                                CELL_ITER_IGNORE_HIDDEN | CELL_ITER_IGNORE_BLANK,
961
426
                                col, start_row, col, end_row,
962
427
                                (CellIterFunc) cb_filter_find_items, &data);
 
428
                        data.target_sheet = target_sheet;
963
429
                        sheet_foreach_cell_in_range (filter->sheet,
964
430
                                CELL_ITER_IGNORE_HIDDEN,
965
431
                                col, start_row, col, end_row,
966
432
                                (CellIterFunc) cb_hide_unwanted_items, &data);
967
433
                }
968
434
        } else
969
 
                g_warning ("Invalid operator %d", field->cond->op[0]);
970
 
}
971
 
 
972
 
static void
973
 
filter_field_set_active (GnmFilterField *field)
974
 
{
975
 
        GList *ptr;
976
 
        SheetObject *so = &field->parent;
977
 
 
978
 
        for (ptr = so->realized_list; ptr; ptr = ptr->next)
979
 
                filter_field_arrow_format (field,
980
 
                        g_object_get_data (ptr->data, ARROW_ID));
981
 
}
 
435
                g_warning ("Invalid operator %d", cond->op[0]);
 
436
}
 
437
 
 
438
enum {
 
439
        COND_CHANGED,
 
440
        LAST_SIGNAL
 
441
};
 
442
 
 
443
static guint signals [LAST_SIGNAL] = { 0 };
 
444
 
 
445
typedef struct {
 
446
        SheetObjectClass parent;
 
447
 
 
448
        void (*cond_changed) (GnmFilterCombo *);
 
449
} GnmFilterComboClass;
 
450
 
 
451
static void
 
452
gnm_filter_combo_finalize (GObject *object)
 
453
{
 
454
        GnmFilterCombo *fcombo = GNM_FILTER_COMBO (object);
 
455
        GObjectClass *parent;
 
456
        if (fcombo->cond != NULL) {
 
457
                gnm_filter_condition_unref (fcombo->cond);
 
458
                fcombo->cond = NULL;
 
459
        }
 
460
        parent = g_type_class_peek (SHEET_OBJECT_TYPE);
 
461
        parent->finalize (object);
 
462
}
 
463
 
 
464
static void
 
465
gnm_filter_combo_init (SheetObject *so)
 
466
{
 
467
        /* keep the arrows from wandering with their cells */
 
468
        so->flags &= ~SHEET_OBJECT_MOVE_WITH_CELLS;
 
469
}
 
470
static SheetObjectView *
 
471
gnm_filter_combo_foo_view_new (SheetObject *so, SheetObjectViewContainer *container)
 
472
{
 
473
        return gnm_cell_combo_foo_view_new (so,
 
474
                gnm_filter_combo_foo_view_get_type (), container);
 
475
}
 
476
static void
 
477
gnm_filter_combo_class_init (GObjectClass *gobject_class)
 
478
{
 
479
        SheetObjectClass *so_class = SHEET_OBJECT_CLASS (gobject_class);
 
480
 
 
481
        /* Object class method overrides */
 
482
        gobject_class->finalize = gnm_filter_combo_finalize;
 
483
 
 
484
        /* SheetObject class method overrides */
 
485
        so_class->new_view      = gnm_filter_combo_foo_view_new;
 
486
        so_class->read_xml_dom  = NULL;
 
487
        so_class->write_xml_sax = NULL;
 
488
        so_class->print         = NULL;
 
489
        so_class->copy          = NULL;
 
490
 
 
491
        signals[COND_CHANGED] = g_signal_new ("cond-changed",
 
492
                 GNM_FILTER_COMBO_TYPE,
 
493
                 G_SIGNAL_RUN_LAST,
 
494
                 G_STRUCT_OFFSET (GnmFilterComboClass, cond_changed),
 
495
                 NULL, NULL,
 
496
                 g_cclosure_marshal_VOID__VOID,
 
497
                 G_TYPE_NONE, 0);
 
498
}
 
499
 
 
500
GSF_CLASS (GnmFilterCombo, gnm_filter_combo,
 
501
           gnm_filter_combo_class_init, gnm_filter_combo_init,
 
502
           SHEET_OBJECT_TYPE);
982
503
 
983
504
/*************************************************************************/
984
505
 
986
507
gnm_filter_add_field (GnmFilter *filter, int i)
987
508
{
988
509
        /* pretend to fill the cell, then clip the X start later */
989
 
        static SheetObjectAnchorType const anchor_types [4] = {
990
 
                SO_ANCHOR_PERCENTAGE_FROM_COLROW_START,
991
 
                SO_ANCHOR_PERCENTAGE_FROM_COLROW_START,
992
 
                SO_ANCHOR_PERCENTAGE_FROM_COLROW_END,
993
 
                SO_ANCHOR_PERCENTAGE_FROM_COLROW_END
994
 
        };
995
 
        static float const offsets [4] = { .0, .0, 0., 0. };
 
510
        static float const a_offsets [4] = { .0, .0, 1., 1. };
996
511
        int n;
997
512
        GnmRange tmp;
998
513
        SheetObjectAnchor anchor;
999
 
        GnmFilterField *field = g_object_new (filter_field_get_type (), NULL);
 
514
        GnmFilterCombo *fcombo = g_object_new (GNM_FILTER_COMBO_TYPE, NULL);
1000
515
 
1001
 
        field->filter = filter;
 
516
        fcombo->filter = filter;
1002
517
        tmp.start.row = tmp.end.row = filter->r.start.row;
1003
518
        tmp.start.col = tmp.end.col = filter->r.start.col + i;
1004
 
        sheet_object_anchor_init (&anchor, &tmp, offsets, anchor_types,
1005
 
                                  GOD_ANCHOR_DIR_DOWN_RIGHT);
1006
 
        sheet_object_set_anchor (&field->parent, &anchor);
1007
 
        sheet_object_set_sheet (&field->parent, filter->sheet);
 
519
        sheet_object_anchor_init (&anchor, &tmp, a_offsets, NULL,
 
520
                GOD_ANCHOR_DIR_DOWN_RIGHT);
 
521
        sheet_object_set_anchor (SHEET_OBJECT (fcombo), &anchor);
 
522
        sheet_object_set_sheet (SHEET_OBJECT (fcombo), filter->sheet);
1008
523
 
1009
524
        g_ptr_array_add (filter->fields, NULL);
1010
525
        for (n = filter->fields->len; --n > i ; )
1011
526
                g_ptr_array_index (filter->fields, n) =
1012
527
                        g_ptr_array_index (filter->fields, n-1);
1013
 
        g_ptr_array_index (filter->fields, n) = field;
1014
 
        g_object_unref (G_OBJECT (field));
 
528
        g_ptr_array_index (filter->fields, n) = fcombo;
 
529
        g_object_unref (G_OBJECT (fcombo));
1015
530
}
1016
531
 
1017
532
/**
1019
534
 * @sheet :
1020
535
 * @r :
1021
536
 *
1022
 
 * Init a filter
 
537
 * Init a filter and add it to @sheet
1023
538
 **/
1024
539
GnmFilter *
1025
540
gnm_filter_new (Sheet *sheet, GnmRange const *r)
1046
561
        return filter;
1047
562
}
1048
563
 
 
564
/**
 
565
 * gnm_filter_dup :
 
566
 * @src : #GnmFilter
 
567
 * @sheet : #Sheet
 
568
 *
 
569
 * Duplicate @src into @sheet
 
570
 **/
 
571
GnmFilter *
 
572
gnm_filter_dup (GnmFilter const *src, Sheet *sheet)
 
573
{
 
574
        int i;
 
575
        GnmFilter *dst;
 
576
 
 
577
        g_return_val_if_fail (src != NULL, NULL);
 
578
        g_return_val_if_fail (IS_SHEET (sheet), NULL);
 
579
 
 
580
        dst = g_new0 (GnmFilter, 1);
 
581
        dst->sheet = sheet;
 
582
 
 
583
        dst->is_active = src->is_active;
 
584
        dst->r = src->r;
 
585
        dst->fields = g_ptr_array_new ();
 
586
 
 
587
        for (i = 0 ; i < range_width (&dst->r); i++) {
 
588
                gnm_filter_add_field (dst, i);
 
589
                gnm_filter_set_condition (dst, i,
 
590
                        gnm_filter_condition_dup (
 
591
                                gnm_filter_get_condition (src, i)),
 
592
                        FALSE);
 
593
        }
 
594
 
 
595
        sheet->filters = g_slist_prepend (sheet->filters, dst);
 
596
        sheet->priv->filters_changed = TRUE;
 
597
 
 
598
        return dst;
 
599
}
1049
600
void
1050
601
gnm_filter_free (GnmFilter *filter)
1051
602
{
1091
642
GnmFilterCondition const *
1092
643
gnm_filter_get_condition (GnmFilter const *filter, unsigned i)
1093
644
{
1094
 
        GnmFilterField *field;
 
645
        GnmFilterCombo *fcombo;
1095
646
 
1096
647
        g_return_val_if_fail (filter != NULL, NULL);
1097
648
        g_return_val_if_fail (i < filter->fields->len, NULL);
1098
649
 
1099
 
        field = g_ptr_array_index (filter->fields, i);
1100
 
        return field->cond;
 
650
        fcombo = g_ptr_array_index (filter->fields, i);
 
651
        return fcombo->cond;
1101
652
}
1102
653
 
1103
654
/**
1104
655
 * gnm_filter_set_condition :
1105
656
 * @filter :
1106
657
 * @i :
1107
 
 * @cond :
 
658
 * @cond : #GnmFilterCondition
1108
659
 * @apply :
1109
660
 *
 
661
 * Change the @i-th condition of @filter to @cond.  If @apply is
 
662
 * TRUE @filter is used to set the visibility of the rows in @filter::sheet
 
663
 *
 
664
 * Absorbs the reference to @cond.
1110
665
 **/
1111
666
void
1112
667
gnm_filter_set_condition (GnmFilter *filter, unsigned i,
1113
668
                          GnmFilterCondition *cond,
1114
669
                          gboolean apply)
1115
670
{
1116
 
        GnmFilterField *field;
 
671
        GnmFilterCombo *fcombo;
1117
672
        gboolean set_infilter = FALSE;
1118
673
        gboolean existing_cond = FALSE;
1119
674
        int r;
1121
676
        g_return_if_fail (filter != NULL);
1122
677
        g_return_if_fail (i < filter->fields->len);
1123
678
 
1124
 
        field = g_ptr_array_index (filter->fields, i);
 
679
        fcombo = g_ptr_array_index (filter->fields, i);
1125
680
 
1126
 
        if (field->cond != NULL) {
 
681
        if (fcombo->cond != NULL) {
1127
682
                existing_cond = TRUE;
1128
 
                gnm_filter_condition_unref (field->cond);
 
683
                gnm_filter_condition_unref (fcombo->cond);
1129
684
        }
1130
 
        field->cond = cond;
1131
 
        filter_field_set_active (field);
 
685
        fcombo->cond = cond;
 
686
        g_signal_emit (G_OBJECT (fcombo), signals [COND_CHANGED], 0);
1132
687
 
1133
688
        if (apply) {
1134
689
                /* if there was an existing cond then we need to do
1141
696
                        colrow_set_visibility (filter->sheet, FALSE, TRUE,
1142
697
                                filter->r.start.row + 1, filter->r.end.row);
1143
698
                        for (i = 0 ; i < filter->fields->len ; i++)
1144
 
                                filter_field_apply (g_ptr_array_index (filter->fields, i));
 
699
                                gnm_filter_combo_apply (g_ptr_array_index (filter->fields, i),
 
700
                                        filter->sheet);
1145
701
                } else
1146
702
                        /* When adding a new cond all we need to do is
1147
703
                         * apply that filter */
1148
 
                        filter_field_apply (field);
 
704
                        gnm_filter_combo_apply (fcombo, filter->sheet);
1149
705
        }
1150
706
 
1151
707
        /* set the activity flag and potentially activate the
1152
708
         * in_filter flags in the rows */
1153
709
        if (cond == NULL) {
1154
710
                for (i = 0 ; i < filter->fields->len ; i++) {
1155
 
                        field = g_ptr_array_index (filter->fields, i);
1156
 
                        if (field->cond != NULL)
 
711
                        fcombo = g_ptr_array_index (filter->fields, i);
 
712
                        if (fcombo->cond != NULL)
1157
713
                                break;
1158
714
                }
1159
715
                if (i >= filter->fields->len) {
1198
754
}
1199
755
 
1200
756
/**
1201
 
 * sheet_filter_guess_region :
 
757
 * gnm_sheet_filter_guess_region :
1202
758
 * @sheet : #Sheet
1203
759
 * @range : #GnmRange
1204
760
 *
1205
761
 **/
1206
762
void
1207
 
sheet_filter_guess_region (Sheet *sheet, GnmRange *region)
 
763
gnm_sheet_filter_guess_region (Sheet *sheet, GnmRange *region)
1208
764
{
1209
765
        int col;
1210
766
        int end_row;
1253
809
}
1254
810
 
1255
811
/**
1256
 
 * sheet_filter_insdel_colrow :
 
812
 * gnm_sheet_filter_insdel_colrow :
1257
813
 * @sheet :
1258
814
 * @is_cols :
1259
815
 * @is_insert :
1263
819
 * Adjust filters as necessary to handle col/row insertions and deletions
1264
820
 **/
1265
821
void
1266
 
sheet_filter_insdel_colrow (Sheet *sheet, gboolean is_cols, gboolean is_insert,
1267
 
                            int start, int count)
 
822
gnm_sheet_filter_insdel_colrow (Sheet *sheet,
 
823
                                gboolean is_cols, gboolean is_insert,
 
824
                                int start, int count)
1268
825
{
1269
826
        GSList *ptr, *filters;
1270
827
        GnmFilter *filter;