~kamstrup/dee/sorted

« back to all changes in this revision

Viewing changes to dee/dee-filter.c

  • Committer: Mikkel Kamstrup Erlandsen
  • Date: 2011-12-15 12:28:43 UTC
  • mfrom: (320 dee)
  • mto: This revision was merged to the branch mainline in revision 321.
  • Revision ID: mikkel.kamstrup@gmail.com-20111215122843-u0iujfnovviqx9dz
Sync with trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 */
20
20
 
21
21
/**
22
 
 * SECTION:dee-filters
 
22
 * SECTION:dee-filter
23
23
 * @title: Filters
24
24
 * @short_description: A suite of simple #DeeFilter<!-- -->s for use with #DeeFilterModel<!-- -->s
25
25
 * @include: dee.h
52
52
#include <config.h>
53
53
#endif
54
54
 
 
55
#include <string.h> // memset()
 
56
 
55
57
#include "dee-filter-model.h"
 
58
#include "dee-filter.h"
56
59
#include "trace-log.h"
57
60
 
58
61
/* The CollatorFilter stores collation keys for the columns in a DeeModelTag */
79
82
/*
80
83
 * Private impl
81
84
 */
82
 
static void _dee_filter_collator_map_notify (DeeModel *orig_model,
83
 
                                             DeeModelIter *orig_iter,
84
 
                                             DeeFilterModel *filter_model,
85
 
                                             gpointer user_data);
 
85
static gboolean _dee_filter_collator_map_notify (DeeModel *orig_model,
 
86
                                                 DeeModelIter *orig_iter,
 
87
                                                 DeeFilterModel *filter_model,
 
88
                                                 gpointer user_data);
86
89
 
87
 
static void _dee_filter_collator_desc_map_notify (DeeModel *orig_model,
88
 
                                                  DeeModelIter *orig_iter,
89
 
                                                  DeeFilterModel *filter_model,
90
 
                                                  gpointer user_data);
 
90
static gboolean _dee_filter_collator_desc_map_notify (DeeModel *orig_model,
 
91
                                                      DeeModelIter *orig_iter,
 
92
                                                      DeeFilterModel *filter_model,
 
93
                                                      gpointer user_data);
91
94
 
92
95
static void
93
96
_dee_filter_collator_map_func (DeeModel *orig_model,
137
140
 
138
141
}
139
142
 
140
 
static void
 
143
static gboolean
141
144
_dee_filter_collator_map_notify (DeeModel *orig_model,
142
145
                                 DeeModelIter *orig_iter,
143
146
                                 DeeFilterModel *filter_model,
148
151
  const gchar    *column_value, *test_value;
149
152
  gchar          *collation_key;
150
153
 
151
 
  g_return_if_fail (user_data != NULL);
152
 
  g_return_if_fail (orig_iter != NULL);
 
154
  g_return_val_if_fail (user_data != NULL, FALSE);
 
155
  g_return_val_if_fail (orig_iter != NULL, FALSE);
153
156
 
154
157
  filter = (CollatorFilter *) user_data;
155
158
 
180
183
    {
181
184
      dee_filter_model_append_iter(filter_model, orig_iter);
182
185
    }
 
186
    
 
187
  return TRUE;
183
188
}
184
189
 
185
 
static void
 
190
static gboolean
186
191
_dee_filter_collator_desc_map_notify (DeeModel *orig_model,
187
192
                                 DeeModelIter *orig_iter,
188
193
                                 DeeFilterModel *filter_model,
193
198
  const gchar    *column_value, *test_value;
194
199
  gchar          *collation_key;
195
200
 
196
 
  g_return_if_fail (user_data != NULL);
197
 
  g_return_if_fail (orig_iter != NULL);
 
201
  g_return_val_if_fail (user_data != NULL, FALSE);
 
202
  g_return_val_if_fail (orig_iter != NULL, FALSE);
198
203
 
199
204
  filter = (CollatorFilter *) user_data;
200
205
 
225
230
    {
226
231
      dee_filter_model_append_iter(filter_model, orig_iter);
227
232
    }
 
233
  
 
234
  return TRUE;
228
235
}
229
236
 
230
237
static void
256
263
    }
257
264
}
258
265
 
259
 
static void
 
266
static gboolean
260
267
_dee_filter_key_map_notify (DeeModel *orig_model,
261
268
                            DeeModelIter *orig_iter,
262
269
                            DeeFilterModel *filter_model,
265
272
  KeyFilter      *filter;
266
273
  const gchar    *val;
267
274
 
268
 
  g_return_if_fail (user_data != NULL);
 
275
  g_return_val_if_fail (user_data != NULL, FALSE);
269
276
 
270
277
  filter = (KeyFilter *) user_data;
271
278
  val = dee_model_get_string (orig_model, orig_iter, filter->column);
272
279
 
273
280
  /* Ignore rows that don't match the key */
274
281
  if (g_strcmp0 (filter->key, val) != 0)
275
 
    return;
 
282
    return FALSE;
276
283
 
277
284
  dee_filter_model_insert_iter_with_original_order (filter_model, orig_iter);
 
285
  return TRUE;
278
286
}
279
287
 
280
288
static void
303
311
    }
304
312
}
305
313
 
306
 
static void
 
314
static gboolean
307
315
_dee_filter_value_map_notify (DeeModel *orig_model,
308
316
                              DeeModelIter *orig_iter,
309
317
                              DeeFilterModel *filter_model,
312
320
  ValueFilter    *filter;
313
321
  GVariant       *val;
314
322
 
315
 
  g_return_if_fail (user_data != NULL);
 
323
  g_return_val_if_fail (user_data != NULL, FALSE);
316
324
 
317
325
  filter = (ValueFilter *) user_data;
318
326
  val = dee_model_get_value (orig_model, orig_iter, filter->column);
319
327
 
320
328
  /* Ignore rows that don't match the value */
321
329
  if (!g_variant_equal (filter->value, val))
322
 
    return;
 
330
    return FALSE;
323
331
 
324
332
  dee_filter_model_insert_iter_with_original_order (filter_model, orig_iter);
 
333
  return TRUE;
325
334
}
326
335
 
327
336
static void
354
363
    }
355
364
}
356
365
 
357
 
static void
 
366
static gboolean
358
367
_dee_filter_regex_map_notify (DeeModel *orig_model,
359
368
                              DeeModelIter *orig_iter,
360
369
                              DeeFilterModel *filter_model,
363
372
  RegexFilter    *filter;
364
373
  const gchar    *val;
365
374
 
366
 
  g_return_if_fail (user_data != NULL);
 
375
  g_return_val_if_fail (user_data != NULL, FALSE);
367
376
 
368
377
  filter = (RegexFilter *) user_data;
369
378
  val = dee_model_get_string (orig_model, orig_iter, filter->column);
370
379
 
371
380
  /* Ignore rows that don't match the key */
372
381
  if (!g_regex_match (filter->regex, val, 0, NULL))
373
 
    return;
 
382
    return FALSE;
374
383
 
375
384
  dee_filter_model_insert_iter_with_original_order (filter_model, orig_iter);
 
385
  return TRUE;
376
386
}
377
387
 
378
388
static void
401
411
 */
402
412
 
403
413
/**
 
414
 * dee_filter_notify:
 
415
 * @filter: The filter to apply
 
416
 * @orig_iter: The #DeeModelIter added to @orig_model
 
417
 * @orig_model: The model that is being filtered
 
418
 * @filter_model: The #DeeFilterModel that holds the
 
419
 *                filtered subset of @orig_model
 
420
 *
 
421
 * Call the #DeeFilterMapNotify function of a #DeeFilter.
 
422
 * When using a #DeeFilterModel you should not call this method yourself.
 
423
 *
 
424
 * Returns: The return value from the #DeeFilterMapNotify. That is; %TRUE
 
425
 *          if @orig_iter was added to @filter_model
 
426
 */
 
427
gboolean
 
428
dee_filter_notify (DeeFilter      *filter,
 
429
                   DeeModelIter   *orig_iter,
 
430
                   DeeModel       *orig_model,
 
431
                   DeeFilterModel *filter_model)
 
432
{
 
433
  g_return_val_if_fail (filter != NULL, FALSE);
 
434
 
 
435
  return filter->map_notify (orig_model, orig_iter,
 
436
                             filter_model, filter->userdata);
 
437
}
 
438
 
 
439
/**
 
440
 * dee_filter_map:
 
441
 * @filter: The filter to apply
 
442
 * @orig_model: The model that is being filtered
 
443
 * @filter_model: The #DeeFilterModel that holds the
 
444
 *                filtered subset of @orig_model
 
445
 *
 
446
 * Call the #DeeFilterMapFunc function of a #DeeFilter.
 
447
 * When using a #DeeFilterModel you should not call this method yourself.
 
448
 */
 
449
void
 
450
dee_filter_map (DeeFilter      *filter,
 
451
                DeeModel       *orig_model,
 
452
                DeeFilterModel *filter_model)
 
453
{
 
454
  g_return_if_fail (filter != NULL);
 
455
 
 
456
  filter->map_func (orig_model, filter_model, filter->userdata);
 
457
}
 
458
 
 
459
/**
 
460
 * dee_filter_destroy:
 
461
 * @filter: The filter to destroy
 
462
 *
 
463
 * Call the #GDestroyNotify function on the userdata pointer of a #DeeFilter
 
464
 * (if the destroy member is set, that is).
 
465
 *
 
466
 * When using a #DeeFilterModel you should not call this method yourself.
 
467
 *
 
468
 * This method will not free the memory allocated for @filter.
 
469
 */
 
470
void
 
471
dee_filter_destroy (DeeFilter *filter)
 
472
{
 
473
  g_return_if_fail (filter != NULL);
 
474
 
 
475
  if (filter->destroy)
 
476
    filter->destroy (filter->userdata);
 
477
}
 
478
 
 
479
/**
 
480
 * dee_filter_new:
 
481
 * @map_func: (scope notified): The #DeeFilterMapFunc to use for the filter
 
482
 * @map_notify: (scope notified): The #DeeFilterMapNotify to use for the filter
 
483
 * @userdata: (closure) (allow-none): The user data to pass to
 
484
                                      @map_func and @map_notify
 
485
 * @destroy: (allow-none): The #GDestroyNotify to call on
 
486
 *                                        @userdata when disposing of the filter
 
487
 * @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
 
488
 *                     This struct will zeroed and configured with the filter
 
489
 *                     parameters
 
490
 *
 
491
 * Create a new #DeeFilter with the given parameters. This call will zero
 
492
 * the @out_filter struct.
 
493
 *
 
494
 */
 
495
void
 
496
dee_filter_new (DeeFilterMapFunc   map_func,
 
497
                DeeFilterMapNotify map_notify,
 
498
                GDestroyNotify     destroy,
 
499
                gpointer           userdata,
 
500
                DeeFilter         *out_filter)
 
501
{
 
502
  g_return_if_fail (map_func != NULL);
 
503
  g_return_if_fail (map_notify != NULL);
 
504
  g_return_if_fail (out_filter != NULL);
 
505
 
 
506
  memset (out_filter, 0, sizeof (DeeFilter));
 
507
 
 
508
  out_filter->map_func = map_func;
 
509
  out_filter->map_notify = map_notify;
 
510
  out_filter->userdata = userdata;
 
511
  out_filter->destroy = destroy;
 
512
}
 
513
 
 
514
/**
404
515
 * dee_filter_new_collator:
405
516
 * @column: The index of a column containing the strings to sort after
 
517
 * @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
 
518
 *                     This struct will zeroed and configured with the filter
 
519
 *                     parameters
406
520
 *
407
521
 * Create a #DeeFilter that takes string values from a column in the model
408
522
 * and builds a #DeeFilterModel with the rows sorted according to the
409
523
 * collation rules of the current locale.
410
 
 *
411
 
 * Returns: (transfer full): A newly allocated #DeeFilter. Do not modify it.
412
 
 *          Free with g_free().
413
524
 */
414
 
DeeFilter*
415
 
dee_filter_new_collator    (guint column)
 
525
void
 
526
dee_filter_new_collator    (guint      column,
 
527
                            DeeFilter *out_filter)
416
528
{
417
 
  DeeFilter      *filter;
418
529
  CollatorFilter *collator;
419
530
 
420
 
  filter = g_new0 (DeeFilter, 1);
421
 
  filter->map_func = _dee_filter_collator_map_func;
422
 
  filter->map_notify = _dee_filter_collator_map_notify;
423
 
 
424
531
  collator = g_new0 (CollatorFilter, 1);
425
532
  collator->column = column;
426
533
 
427
 
  filter->destroy = (GDestroyNotify) g_free;
428
 
  filter->user_data =collator;
429
 
 
430
 
  return filter;
 
534
  dee_filter_new (_dee_filter_collator_map_func,
 
535
                  _dee_filter_collator_map_notify,
 
536
                  (GDestroyNotify) g_free,
 
537
                  collator,
 
538
                  out_filter);
431
539
}
432
540
 
433
541
/**
434
542
 * dee_filter_new_collator_desc:
435
543
 * @column: The index of a column containing the strings to sort after
 
544
 * @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
 
545
 *                     This struct will zeroed and configured with the filter
 
546
 *                     parameters
436
547
 *
437
548
 * Create a #DeeFilter that takes string values from a column in the model
438
549
 * and builds a #DeeFilterModel with the rows sorted descending according to the
439
550
 * collation rules of the current locale.
440
 
 *
441
 
 * Returns: (transfer full): A newly allocated #DeeFilter. Do not modify it.
442
 
 *          Free with g_free().
443
551
 */
444
 
DeeFilter*
445
 
dee_filter_new_collator_desc    (guint column)
 
552
void
 
553
dee_filter_new_collator_desc    (guint      column,
 
554
                                 DeeFilter *out_filter)
446
555
{
447
 
  DeeFilter      *filter;
448
556
  CollatorFilter *collator; 
449
 
 
450
 
  filter = g_new0 (DeeFilter, 1); 
451
 
  filter->map_func = _dee_filter_collator_desc_map_func;
452
 
  filter->map_notify = _dee_filter_collator_desc_map_notify;
453
 
 
 
557
 
454
558
  collator = g_new0 (CollatorFilter, 1);
455
559
  collator->column = column;
456
560
 
457
 
  filter->destroy = (GDestroyNotify) g_free;
458
 
  filter->user_data =collator;
459
 
 
460
 
  return filter;
 
561
  dee_filter_new (_dee_filter_collator_desc_map_func,
 
562
                  _dee_filter_collator_desc_map_notify,
 
563
                  (GDestroyNotify) g_free,
 
564
                  collator,
 
565
                  out_filter);
461
566
462
567
 
463
568
 
464
569
/**
465
570
 * dee_filter_new_for_key_column:
466
571
 * @column: The index of a column containing the string key to match
 
572
 * @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
 
573
 *                     This struct will zeroed and configured with the filter
 
574
 *                     parameters
467
575
 *
468
576
 * Create a #DeeFilter that only includes rows from the original model
469
577
 * which has an exact match on some string column. A #DeeFilterModel created
470
578
 * with this filter will be ordered in accordance with its parent model.
471
 
 *
472
 
 * Returns: (transfer full): A newly allocated #DeeFilter. Do not modify it.
473
 
 *          Free with g_free().
474
579
 */
475
 
DeeFilter*
476
 
dee_filter_new_for_key_column    (guint column, const gchar *key)
 
580
void
 
581
dee_filter_new_for_key_column    (guint        column,
 
582
                                  const gchar *key,
 
583
                                  DeeFilter   *out_filter)
477
584
{
478
 
  DeeFilter      *filter;
479
585
  KeyFilter      *key_filter;
480
586
 
481
 
  filter = g_new0 (DeeFilter, 1);
482
 
  filter->map_func = _dee_filter_key_map_func;
483
 
  filter->map_notify = _dee_filter_key_map_notify;
 
587
  g_return_if_fail (key != NULL);
484
588
 
485
589
  key_filter = g_new0 (KeyFilter, 1);
486
590
  key_filter->column = column;
487
591
  key_filter->key = g_strdup (key);
488
592
 
489
 
  filter->destroy = (GDestroyNotify) key_filter_free;
490
 
  filter->user_data = key_filter;
491
 
 
492
 
  return filter;
 
593
  dee_filter_new (_dee_filter_key_map_func,
 
594
                  _dee_filter_key_map_notify,
 
595
                  (GDestroyNotify) key_filter_free,
 
596
                  key_filter,
 
597
                  out_filter);
493
598
}
494
599
 
495
600
/**
498
603
 * @value: (transfer none): A #GVariant value columns must match exactly.
499
604
 *         The matching semantics are those of g_variant_equal(). If @value
500
605
 *         is floating the ownership will be transfered to the filter
 
606
 * @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
 
607
 *                     This struct will zeroed and configured with the filter
 
608
 *                     parameters
501
609
 *
502
610
 * Create a #DeeFilter that only includes rows from the original model
503
611
 * which match a variant value in a given column. A #DeeFilterModel
507
615
 * value comparison is done using g_variant_equal(). This means you can use
508
616
 * this filter as a convenient fallback when there is no predefined filter
509
617
 * for your column type if raw performance is not paramount.
510
 
 *
511
 
 * Returns: (transfer full): A newly allocated #DeeFilter. Do not modify it.
512
 
 *          Free with g_free().
513
618
 */
514
 
DeeFilter*
515
 
dee_filter_new_for_any_column (guint column, GVariant *value)
 
619
void
 
620
dee_filter_new_for_any_column (guint      column,
 
621
                               GVariant  *value,
 
622
                               DeeFilter *out_filter)
516
623
{
517
 
  DeeFilter      *filter;
518
624
  ValueFilter    *v_filter;
519
625
 
520
 
  g_return_val_if_fail (value != NULL, NULL);
521
 
 
522
 
  filter = g_new0 (DeeFilter, 1);
523
 
  filter->map_func = _dee_filter_value_map_func;
524
 
  filter->map_notify = _dee_filter_value_map_notify;
 
626
  g_return_if_fail (value != NULL);
525
627
 
526
628
  v_filter = g_new0 (ValueFilter, 1);
527
629
  v_filter->column = column;
528
630
  v_filter->value = g_variant_ref_sink (value);
529
631
 
530
 
  filter->destroy = (GDestroyNotify) value_filter_free;
531
 
  filter->user_data = v_filter;
532
 
 
533
 
  return filter;
 
632
  dee_filter_new (_dee_filter_value_map_func,
 
633
                  _dee_filter_value_map_notify,
 
634
                  (GDestroyNotify) value_filter_free,
 
635
                  v_filter,
 
636
                  out_filter);
534
637
}
535
638
 
536
639
/**
537
640
 * dee_filter_new_regex:
538
641
 * @column: The index of a column containing the string to match
539
642
 * @regex: (transfer none):The regular expression @column must match
 
643
 * @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
 
644
 *                     This struct will zeroed and configured with the filter
 
645
 *                     parameters
540
646
 *
541
647
 * Create a #DeeFilter that only includes rows from the original model
542
648
 * which match a regular expression on some string column. A #DeeFilterModel
543
649
 * created with this filter will be ordered in accordance with its parent model.
544
 
 *
545
 
 * Returns: (transfer full): A newly allocated #DeeFilter. Do not modify it.
546
 
 *          Free with g_free().
547
650
 */
548
 
DeeFilter*
549
 
dee_filter_new_regex (guint column, GRegex *regex)
 
651
void
 
652
dee_filter_new_regex (guint      column,
 
653
                      GRegex    *regex,
 
654
                      DeeFilter *out_filter)
550
655
{
551
 
  DeeFilter      *filter;
552
656
  RegexFilter    *r_filter;
553
657
 
554
 
  g_return_val_if_fail (regex != NULL, NULL);
555
 
 
556
 
  filter = g_new0 (DeeFilter, 1);
557
 
  filter->map_func = _dee_filter_regex_map_func;
558
 
  filter->map_notify = _dee_filter_regex_map_notify;
 
658
  g_return_if_fail (regex != NULL);
559
659
 
560
660
  r_filter = g_new0 (RegexFilter, 1);
561
661
  r_filter->column = column;
562
662
  r_filter->regex = g_regex_ref (regex);
563
663
 
564
 
  filter->destroy = (GDestroyNotify) regex_filter_free;
565
 
  filter->user_data = r_filter;
566
 
 
567
 
  return filter;
 
664
  dee_filter_new (_dee_filter_regex_map_func,
 
665
                  _dee_filter_regex_map_notify,
 
666
                  (GDestroyNotify) regex_filter_free,
 
667
                  r_filter,
 
668
                  out_filter);
568
669
}
 
670