~elementary-os/ubuntu-package-imports/mutter-bionic

« back to all changes in this revision

Viewing changes to clutter/clutter/deprecated/clutter-list-model.c

  • Committer: RabbitBot
  • Date: 2018-04-11 14:49:36 UTC
  • Revision ID: rabbitbot@elementary.io-20180411144936-hgymqa9d8d1xfpbh
Initial import, version 3.28.0-2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Clutter.
 
3
 *
 
4
 * An OpenGL based 'interactive canvas' library.
 
5
 *
 
6
 * Authored By Matthew Allum  <mallum@openedhand.com>
 
7
 *             Neil Jagdish Patel <njp@o-hand.com>
 
8
 *             Emmanuele Bassi <ebassi@openedhand.com>
 
9
 *
 
10
 * Copyright (C) 2006 OpenedHand
 
11
 *
 
12
 * This library is free software; you can redistribute it and/or
 
13
 * modify it under the terms of the GNU Lesser General Public
 
14
 * License as published by the Free Software Foundation; either
 
15
 * version 2 of the License, or (at your option) any later version.
 
16
 *
 
17
 * This library is distributed in the hope that it will be useful,
 
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
20
 * Lesser General Public License for more details.
 
21
 *
 
22
 * You should have received a copy of the GNU Lesser General Public
 
23
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 
24
 *
 
25
 *
 
26
 */
 
27
 
 
28
/**
 
29
 * SECTION:clutter-list-model
 
30
 * @short_description: List model implementation
 
31
 *
 
32
 * #ClutterListModel is a #ClutterModel implementation provided by
 
33
 * Clutter. #ClutterListModel uses a #GSequence for storing the
 
34
 * values for each row, so it's optimized for insertion and look up
 
35
 * in sorted lists.
 
36
 *
 
37
 * #ClutterListModel is available since Clutter 0.6
 
38
 *
 
39
 * Deprecated: 1.24: Use a #GListStore instance containing a custom
 
40
 *   object type with properties for each column instead.
 
41
 */
 
42
 
 
43
#ifdef HAVE_CONFIG_H
 
44
#include "clutter-build-config.h"
 
45
#endif
 
46
 
 
47
#include <stdlib.h>
 
48
#include <string.h>
 
49
 
 
50
#include <glib-object.h>
 
51
 
 
52
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
 
53
#include "clutter-list-model.h"
 
54
 
 
55
#include "clutter-model.h"
 
56
#include "clutter-model-private.h"
 
57
#include "clutter-private.h"
 
58
#include "clutter-debug.h"
 
59
 
 
60
#define CLUTTER_TYPE_LIST_MODEL_ITER                 \
 
61
        (clutter_list_model_iter_get_type())
 
62
#define CLUTTER_LIST_MODEL_ITER(obj)                 \
 
63
        (G_TYPE_CHECK_INSTANCE_CAST((obj),           \
 
64
         CLUTTER_TYPE_LIST_MODEL_ITER,               \
 
65
         ClutterListModelIter))
 
66
#define CLUTTER_IS_LIST_MODEL_ITER(obj)              \
 
67
        (G_TYPE_CHECK_INSTANCE_TYPE((obj),           \
 
68
         CLUTTER_TYPE_LIST_MODEL_ITER))
 
69
#define CLUTTER_LIST_MODEL_ITER_CLASS(klass)         \
 
70
        (G_TYPE_CHECK_CLASS_CAST ((klass),           \
 
71
         CLUTTER_TYPE_LIST_MODEL_ITER,               \
 
72
         ClutterListModelIterClass))
 
73
#define CLUTTER_IS_LIST_MODEL_ITER_CLASS(klass)      \
 
74
        (G_TYPE_CHECK_CLASS_TYPE ((klass),           \
 
75
         CLUTTER_TYPE_LIST_MODEL_ITER))
 
76
#define CLUTTER_LIST_MODEL_ITER_GET_CLASS(obj)       \
 
77
        (G_TYPE_INSTANCE_GET_CLASS ((obj),           \
 
78
         CLUTTER_TYPE_LIST_MODEL_ITER,               \
 
79
         ClutterListModelIterClass))
 
80
 
 
81
typedef struct _ClutterListModelIter    ClutterListModelIter;
 
82
typedef struct _ClutterModelIterClass   ClutterListModelIterClass;
 
83
 
 
84
struct _ClutterListModelPrivate
 
85
{
 
86
  GSequence *sequence;
 
87
 
 
88
  ClutterModelIter *temp_iter;
 
89
};
 
90
 
 
91
struct _ClutterListModelIter
 
92
{
 
93
  ClutterModelIter parent_instance;
 
94
 
 
95
  GSequenceIter *seq_iter;
 
96
};
 
97
 
 
98
 
 
99
 
 
100
GType clutter_list_model_iter_get_type (void);
 
101
 
 
102
/*
 
103
 * ClutterListModel
 
104
 */
 
105
 
 
106
G_DEFINE_TYPE (ClutterListModelIter,
 
107
               clutter_list_model_iter,
 
108
               CLUTTER_TYPE_MODEL_ITER)
 
109
 
 
110
static void
 
111
clutter_list_model_iter_get_value (ClutterModelIter *iter,
 
112
                                   guint             column,
 
113
                                   GValue           *value)
 
114
{
 
115
  ClutterListModelIter *iter_default;
 
116
  GValue *values;
 
117
  GValue *iter_value;
 
118
  GValue real_value = G_VALUE_INIT;
 
119
  gboolean converted = FALSE;
 
120
 
 
121
  iter_default = CLUTTER_LIST_MODEL_ITER (iter);
 
122
  g_assert (iter_default->seq_iter != NULL);
 
123
 
 
124
  values = g_sequence_get (iter_default->seq_iter);
 
125
  iter_value = &values[column];
 
126
  g_assert (iter_value != NULL);
 
127
 
 
128
  if (!g_type_is_a (G_VALUE_TYPE (value), G_VALUE_TYPE (iter_value)))
 
129
    {
 
130
      if (!g_value_type_compatible (G_VALUE_TYPE (value), 
 
131
                                    G_VALUE_TYPE (iter_value)) &&
 
132
          !g_value_type_compatible (G_VALUE_TYPE (iter_value), 
 
133
                                    G_VALUE_TYPE (value)))
 
134
        {
 
135
          g_warning ("%s: Unable to convert from %s to %s",
 
136
                     G_STRLOC,
 
137
                     g_type_name (G_VALUE_TYPE (value)),
 
138
                     g_type_name (G_VALUE_TYPE (iter_value)));
 
139
          return;
 
140
        }
 
141
 
 
142
      if (!g_value_transform (iter_value, &real_value))
 
143
        {
 
144
          g_warning ("%s: Unable to make conversion from %s to %s",
 
145
                     G_STRLOC, 
 
146
                     g_type_name (G_VALUE_TYPE (value)),
 
147
                     g_type_name (G_VALUE_TYPE (iter_value)));
 
148
          g_value_unset (&real_value);
 
149
        }
 
150
 
 
151
      converted = TRUE;
 
152
    }
 
153
  
 
154
  if (converted)
 
155
    {
 
156
      g_value_copy (&real_value, value);
 
157
      g_value_unset (&real_value);
 
158
    }
 
159
  else
 
160
    g_value_copy (iter_value, value);
 
161
}
 
162
 
 
163
static void
 
164
clutter_list_model_iter_set_value (ClutterModelIter *iter,
 
165
                                   guint             column,
 
166
                                   const GValue     *value)
 
167
{
 
168
  ClutterListModelIter *iter_default;
 
169
  GValue *values;
 
170
  GValue *iter_value;
 
171
  GValue real_value = G_VALUE_INIT;
 
172
  gboolean converted = FALSE;
 
173
 
 
174
  iter_default = CLUTTER_LIST_MODEL_ITER (iter);
 
175
  g_assert (iter_default->seq_iter != NULL);
 
176
 
 
177
  values = g_sequence_get (iter_default->seq_iter);
 
178
  iter_value = &values[column];
 
179
  g_assert (iter_value != NULL);
 
180
 
 
181
  if (!g_type_is_a (G_VALUE_TYPE (value), G_VALUE_TYPE (iter_value)))
 
182
    {
 
183
      if (!g_value_type_compatible (G_VALUE_TYPE (value), 
 
184
                                    G_VALUE_TYPE (iter_value)) &&
 
185
          !g_value_type_compatible (G_VALUE_TYPE (iter_value), 
 
186
                                    G_VALUE_TYPE (value)))
 
187
        {
 
188
          g_warning ("%s: Unable to convert from %s to %s\n",
 
189
                     G_STRLOC,
 
190
                     g_type_name (G_VALUE_TYPE (value)),
 
191
                     g_type_name (G_VALUE_TYPE (iter_value)));
 
192
          return;
 
193
        }
 
194
 
 
195
      if (!g_value_transform (value, &real_value))
 
196
        {
 
197
          g_warning ("%s: Unable to make conversion from %s to %s\n",
 
198
                     G_STRLOC, 
 
199
                     g_type_name (G_VALUE_TYPE (value)),
 
200
                     g_type_name (G_VALUE_TYPE (iter_value)));
 
201
          g_value_unset (&real_value);
 
202
        }
 
203
 
 
204
      converted = TRUE;
 
205
    }
 
206
 
 
207
  if (converted)
 
208
    {
 
209
      g_value_copy (&real_value, iter_value);
 
210
      g_value_unset (&real_value);
 
211
    }
 
212
  else
 
213
    g_value_copy (value, iter_value);
 
214
}
 
215
 
 
216
static gboolean
 
217
clutter_list_model_iter_is_first (ClutterModelIter *iter)
 
218
{
 
219
  ClutterListModelIter *iter_default;
 
220
  ClutterModel *model;
 
221
  ClutterModelIter *temp_iter;
 
222
  GSequence *sequence;
 
223
  GSequenceIter *begin, *end;
 
224
 
 
225
  iter_default = CLUTTER_LIST_MODEL_ITER (iter);
 
226
  g_assert (iter_default->seq_iter != NULL);
 
227
 
 
228
  model = clutter_model_iter_get_model (iter);
 
229
 
 
230
  sequence = CLUTTER_LIST_MODEL (model)->priv->sequence;
 
231
 
 
232
  begin = g_sequence_get_begin_iter (sequence);
 
233
  end   = iter_default->seq_iter;
 
234
 
 
235
  temp_iter = CLUTTER_LIST_MODEL (model)->priv->temp_iter;
 
236
 
 
237
  while (!g_sequence_iter_is_begin (begin))
 
238
    {
 
239
      CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = begin;
 
240
 
 
241
      if (clutter_model_filter_iter (model, temp_iter))
 
242
        {
 
243
          end = begin;
 
244
          break;
 
245
        }
 
246
 
 
247
      begin = g_sequence_iter_next (begin);
 
248
    }
 
249
 
 
250
  /* This is because the 'begin_iter' is always *before* the last valid
 
251
   * iter, otherwise we'd have endless loops 
 
252
   */
 
253
  end = g_sequence_iter_prev (end);
 
254
 
 
255
  return iter_default->seq_iter == end;
 
256
}
 
257
 
 
258
static gboolean
 
259
clutter_list_model_iter_is_last (ClutterModelIter *iter)
 
260
{
 
261
  ClutterListModelIter *iter_default;
 
262
  ClutterModelIter *temp_iter;
 
263
  ClutterModel *model;
 
264
  GSequence *sequence;
 
265
  GSequenceIter *begin, *end;
 
266
 
 
267
  iter_default = CLUTTER_LIST_MODEL_ITER (iter);
 
268
  g_assert (iter_default->seq_iter != NULL);
 
269
 
 
270
  if (g_sequence_iter_is_end (iter_default->seq_iter))
 
271
    return TRUE;
 
272
 
 
273
  model = clutter_model_iter_get_model (iter);
 
274
 
 
275
  sequence = CLUTTER_LIST_MODEL (model)->priv->sequence;
 
276
 
 
277
  begin = g_sequence_get_end_iter (sequence);
 
278
  begin = g_sequence_iter_prev (begin);
 
279
  end   = iter_default->seq_iter;
 
280
 
 
281
  temp_iter = CLUTTER_LIST_MODEL (model)->priv->temp_iter;
 
282
 
 
283
  while (!g_sequence_iter_is_begin (begin))
 
284
    {
 
285
      CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = begin;
 
286
 
 
287
      if (clutter_model_filter_iter (model, temp_iter))
 
288
        {
 
289
          end = begin;
 
290
          break;
 
291
        }
 
292
 
 
293
      begin = g_sequence_iter_prev (begin);
 
294
    }
 
295
 
 
296
  /* This is because the 'end_iter' is always *after* the last valid iter.
 
297
   * Otherwise we'd have endless loops 
 
298
   */
 
299
  end = g_sequence_iter_next (end);
 
300
 
 
301
  return iter_default->seq_iter == end;
 
302
}
 
303
 
 
304
static ClutterModelIter *
 
305
clutter_list_model_iter_next (ClutterModelIter *iter)
 
306
{
 
307
  ClutterListModelIter *iter_default;
 
308
  ClutterModelIter *temp_iter;
 
309
  ClutterModel *model = NULL;
 
310
  GSequenceIter *filter_next;
 
311
  guint row;
 
312
 
 
313
  iter_default = CLUTTER_LIST_MODEL_ITER (iter);
 
314
  g_assert (iter_default->seq_iter != NULL);
 
315
 
 
316
  model = clutter_model_iter_get_model (iter);
 
317
  row   = clutter_model_iter_get_row (iter);
 
318
 
 
319
  filter_next = g_sequence_iter_next (iter_default->seq_iter);
 
320
  g_assert (filter_next != NULL);
 
321
 
 
322
  temp_iter = CLUTTER_LIST_MODEL (model)->priv->temp_iter;
 
323
 
 
324
  while (!g_sequence_iter_is_end (filter_next))
 
325
    {
 
326
      CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = filter_next;
 
327
 
 
328
      if (clutter_model_filter_iter (model, temp_iter))
 
329
        {
 
330
          row += 1;
 
331
          break;
 
332
        }
 
333
 
 
334
      filter_next = g_sequence_iter_next (filter_next);
 
335
    }
 
336
 
 
337
  if (g_sequence_iter_is_end (filter_next))
 
338
    row += 1;
 
339
 
 
340
  /* update the iterator and return it */
 
341
  _clutter_model_iter_set_row (CLUTTER_MODEL_ITER (iter_default), row);
 
342
  iter_default->seq_iter = filter_next;
 
343
 
 
344
  return CLUTTER_MODEL_ITER (iter_default);
 
345
}
 
346
 
 
347
static ClutterModelIter *
 
348
clutter_list_model_iter_prev (ClutterModelIter *iter)
 
349
{
 
350
  ClutterListModelIter *iter_default;
 
351
  ClutterModelIter *temp_iter;
 
352
  ClutterModel *model;
 
353
  GSequenceIter *filter_prev;
 
354
  guint row;
 
355
 
 
356
  iter_default = CLUTTER_LIST_MODEL_ITER (iter);
 
357
  g_assert (iter_default->seq_iter != NULL);
 
358
 
 
359
  model = clutter_model_iter_get_model (iter);
 
360
  row   = clutter_model_iter_get_row (iter);
 
361
 
 
362
  filter_prev = g_sequence_iter_prev (iter_default->seq_iter);
 
363
  g_assert (filter_prev != NULL);
 
364
 
 
365
  temp_iter = CLUTTER_LIST_MODEL (model)->priv->temp_iter;
 
366
 
 
367
  while (!g_sequence_iter_is_begin (filter_prev))
 
368
    {
 
369
      CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = filter_prev;
 
370
 
 
371
      if (clutter_model_filter_iter (model, temp_iter))
 
372
        {
 
373
          row -= 1;
 
374
          break;
 
375
        }
 
376
 
 
377
      filter_prev = g_sequence_iter_prev (filter_prev);
 
378
    }
 
379
 
 
380
  if (g_sequence_iter_is_begin (filter_prev))
 
381
    row -= 1;
 
382
 
 
383
  /* update the iterator and return it */
 
384
  _clutter_model_iter_set_row (CLUTTER_MODEL_ITER (iter_default), row);
 
385
  iter_default->seq_iter = filter_prev;
 
386
 
 
387
  return CLUTTER_MODEL_ITER (iter_default);
 
388
}
 
389
 
 
390
static ClutterModelIter *
 
391
clutter_list_model_iter_copy (ClutterModelIter *iter)
 
392
{
 
393
  ClutterListModelIter *iter_default;
 
394
  ClutterListModelIter *iter_copy;
 
395
  ClutterModel *model;
 
396
  guint row;
 
397
 
 
398
  iter_default = CLUTTER_LIST_MODEL_ITER (iter);
 
399
 
 
400
  model = clutter_model_iter_get_model (iter);
 
401
  row   = clutter_model_iter_get_row (iter) - 1;
 
402
 
 
403
  iter_copy = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
 
404
                            "model", model,
 
405
                            "row", row,
 
406
                            NULL);
 
407
 
 
408
  /* this is safe, because the seq_iter pointer on the passed
 
409
   * iterator will be always be overwritten in ::next or ::prev
 
410
   */
 
411
  iter_copy->seq_iter = iter_default->seq_iter;
 
412
 
 
413
  return CLUTTER_MODEL_ITER (iter_copy);
 
414
}
 
415
 
 
416
static void
 
417
clutter_list_model_iter_class_init (ClutterListModelIterClass *klass)
 
418
{
 
419
  ClutterModelIterClass *iter_class = CLUTTER_MODEL_ITER_CLASS (klass);
 
420
 
 
421
  iter_class->get_value = clutter_list_model_iter_get_value;
 
422
  iter_class->set_value = clutter_list_model_iter_set_value;
 
423
  iter_class->is_first  = clutter_list_model_iter_is_first;
 
424
  iter_class->is_last   = clutter_list_model_iter_is_last;
 
425
  iter_class->next      = clutter_list_model_iter_next;
 
426
  iter_class->prev      = clutter_list_model_iter_prev;
 
427
  iter_class->copy      = clutter_list_model_iter_copy;
 
428
}
 
429
 
 
430
static void
 
431
clutter_list_model_iter_init (ClutterListModelIter *iter)
 
432
{
 
433
  iter->seq_iter = NULL;
 
434
}
 
435
 
 
436
/*
 
437
 * ClutterListModel
 
438
 */
 
439
 
 
440
G_DEFINE_TYPE_WITH_PRIVATE (ClutterListModel, clutter_list_model, CLUTTER_TYPE_MODEL)
 
441
 
 
442
static ClutterModelIter *
 
443
clutter_list_model_get_iter_at_row (ClutterModel *model,
 
444
                                    guint         row)
 
445
{
 
446
  ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
 
447
  GSequence *sequence = model_default->priv->sequence;
 
448
  GSequenceIter *filter_next;
 
449
  gint seq_length = g_sequence_get_length (sequence);
 
450
  ClutterListModelIter *retval;
 
451
  gint count = -1;
 
452
 
 
453
  if (row >= seq_length)
 
454
    return NULL;
 
455
 
 
456
  retval = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
 
457
                         "model", model,
 
458
                         "row", row,
 
459
                         NULL);
 
460
 
 
461
  /* short-circuit in case we don't have a filter in place */
 
462
  if (!clutter_model_get_filter_set (model))
 
463
    {
 
464
      retval->seq_iter = g_sequence_get_iter_at_pos (sequence, row);
 
465
 
 
466
      return CLUTTER_MODEL_ITER (retval);
 
467
    }
 
468
 
 
469
  filter_next = g_sequence_get_begin_iter (sequence);
 
470
  g_assert (filter_next != NULL);
 
471
 
 
472
  while (!g_sequence_iter_is_end (filter_next))
 
473
    {
 
474
      retval->seq_iter = filter_next;
 
475
 
 
476
      if (clutter_model_filter_iter (model, CLUTTER_MODEL_ITER (retval)))
 
477
        {
 
478
          /* We've found a row that is valid under the filter */
 
479
          count++;
 
480
          if (count == row)
 
481
            break;
 
482
        }
 
483
 
 
484
      filter_next = g_sequence_iter_next (filter_next);
 
485
    }
 
486
 
 
487
  if (count != row)
 
488
    {
 
489
      g_object_unref (retval);
 
490
      return NULL;
 
491
    }
 
492
  return CLUTTER_MODEL_ITER (retval);
 
493
}
 
494
 
 
495
static ClutterModelIter *
 
496
clutter_list_model_insert_row (ClutterModel *model,
 
497
                               gint          index_)
 
498
{
 
499
  ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
 
500
  GSequence *sequence = model_default->priv->sequence;
 
501
  ClutterListModelIter *retval;
 
502
  guint n_columns, i, pos;
 
503
  GValue *values;
 
504
  GSequenceIter *seq_iter;
 
505
 
 
506
  n_columns = clutter_model_get_n_columns (model);
 
507
  values = g_new0 (GValue, n_columns);
 
508
 
 
509
  for (i = 0; i < n_columns; i++)
 
510
    g_value_init (&values[i], clutter_model_get_column_type (model, i));
 
511
 
 
512
  if (index_ < 0)
 
513
    {
 
514
      seq_iter = g_sequence_append (sequence, values);
 
515
      pos = g_sequence_get_length (sequence) - 1;
 
516
    }
 
517
  else if (index_ == 0)
 
518
    {
 
519
      seq_iter = g_sequence_prepend (sequence, values);
 
520
      pos = 0;
 
521
    }
 
522
  else
 
523
    {
 
524
      seq_iter = g_sequence_get_iter_at_pos (sequence, index_);
 
525
      seq_iter = g_sequence_insert_before (seq_iter, values);
 
526
      pos = index_;
 
527
    }
 
528
 
 
529
  retval = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
 
530
                         "model", model,
 
531
                         "row", pos,
 
532
                         NULL);
 
533
  retval->seq_iter = seq_iter;
 
534
 
 
535
  return CLUTTER_MODEL_ITER (retval);
 
536
}
 
537
 
 
538
static void
 
539
clutter_list_model_remove_row (ClutterModel *model,
 
540
                               guint         row)
 
541
{
 
542
  ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
 
543
  GSequence *sequence = model_default->priv->sequence;
 
544
  GSequenceIter *seq_iter;
 
545
  guint pos = 0;
 
546
 
 
547
  seq_iter = g_sequence_get_begin_iter (sequence);
 
548
  while (!g_sequence_iter_is_end (seq_iter))
 
549
    {
 
550
      if (clutter_model_filter_row (model, pos))
 
551
        {
 
552
          if (pos == row)
 
553
            {  
 
554
              ClutterModelIter *iter;
 
555
 
 
556
              iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
 
557
                                   "model", model,
 
558
                                   "row", pos,
 
559
                                   NULL);
 
560
              CLUTTER_LIST_MODEL_ITER (iter)->seq_iter = seq_iter;
 
561
 
 
562
              /* the actual row is removed from the sequence inside
 
563
               * the ::row-removed signal class handler, so that every
 
564
               * handler connected to ::row-removed will still get
 
565
               * a valid iterator, and every signal connected to
 
566
               * ::row-removed with the AFTER flag will get an updated
 
567
               * model
 
568
               */
 
569
              g_signal_emit_by_name (model, "row-removed", iter);
 
570
 
 
571
              g_object_unref (iter);
 
572
 
 
573
              break;
 
574
            }
 
575
        }
 
576
 
 
577
      pos += 1;
 
578
      seq_iter = g_sequence_iter_next (seq_iter);
 
579
    }
 
580
}
 
581
 
 
582
typedef struct
 
583
{
 
584
  ClutterModel *model;
 
585
  guint column;
 
586
  ClutterModelSortFunc func;
 
587
  gpointer data;
 
588
} SortClosure;
 
589
 
 
590
static gint
 
591
sort_model_default (gconstpointer a,
 
592
                    gconstpointer b,
 
593
                    gpointer      data)
 
594
{
 
595
  const GValue *row_a = a;
 
596
  const GValue *row_b = b;
 
597
  SortClosure *clos = data;
 
598
 
 
599
  return clos->func (clos->model,
 
600
                     &row_a[clos->column],
 
601
                     &row_b[clos->column],
 
602
                     clos->data);
 
603
}
 
604
 
 
605
static void
 
606
clutter_list_model_resort (ClutterModel         *model,
 
607
                           ClutterModelSortFunc  func,
 
608
                           gpointer              data)
 
609
{
 
610
  SortClosure sort_closure = { NULL, 0, NULL, NULL };
 
611
 
 
612
  sort_closure.model  = model;
 
613
  sort_closure.column = clutter_model_get_sorting_column (model);
 
614
  sort_closure.func   = func;
 
615
  sort_closure.data   = data;
 
616
 
 
617
  g_sequence_sort (CLUTTER_LIST_MODEL (model)->priv->sequence,
 
618
                   sort_model_default,
 
619
                   &sort_closure);
 
620
}
 
621
 
 
622
static guint
 
623
clutter_list_model_get_n_rows (ClutterModel *model)
 
624
{
 
625
  ClutterListModel *list_model = CLUTTER_LIST_MODEL (model);
 
626
 
 
627
  /* short-circuit in case we don't have a filter in place */
 
628
  if (!clutter_model_get_filter_set (model))
 
629
    return g_sequence_get_length (list_model->priv->sequence);
 
630
 
 
631
  return CLUTTER_MODEL_CLASS (clutter_list_model_parent_class)->get_n_rows (model);
 
632
}
 
633
 
 
634
static void
 
635
clutter_list_model_row_removed (ClutterModel     *model,
 
636
                                ClutterModelIter *iter)
 
637
{
 
638
  ClutterListModelIter *iter_default;
 
639
  guint i, n_columns;
 
640
  GValue *values;
 
641
 
 
642
  n_columns = clutter_model_get_n_columns (model);
 
643
 
 
644
  iter_default = CLUTTER_LIST_MODEL_ITER (iter);
 
645
 
 
646
  values = g_sequence_get (iter_default->seq_iter);
 
647
 
 
648
  for (i = 0; i < n_columns; i++)
 
649
    g_value_unset (&values[i]);
 
650
 
 
651
  g_free (values);
 
652
 
 
653
  g_sequence_remove (iter_default->seq_iter);
 
654
  iter_default->seq_iter = NULL;
 
655
}
 
656
 
 
657
static void
 
658
clutter_list_model_finalize (GObject *gobject)
 
659
{
 
660
  ClutterListModel *model = CLUTTER_LIST_MODEL (gobject);
 
661
  GSequence *sequence = model->priv->sequence;
 
662
  GSequenceIter *iter;
 
663
  guint n_columns, i;
 
664
 
 
665
  n_columns = clutter_model_get_n_columns (CLUTTER_MODEL (gobject));
 
666
 
 
667
  iter = g_sequence_get_begin_iter (sequence);
 
668
  while (!g_sequence_iter_is_end (iter))
 
669
    {
 
670
      GValue *values = g_sequence_get (iter);
 
671
 
 
672
      for (i = 0; i < n_columns; i++)
 
673
        g_value_unset (&values[i]);
 
674
 
 
675
      g_free (values);
 
676
 
 
677
      iter = g_sequence_iter_next (iter);
 
678
    }
 
679
  g_sequence_free (sequence);
 
680
 
 
681
  G_OBJECT_CLASS (clutter_list_model_parent_class)->finalize (gobject);
 
682
}
 
683
 
 
684
static void
 
685
clutter_list_model_dispose (GObject *gobject)
 
686
{
 
687
  ClutterListModel *model = CLUTTER_LIST_MODEL (gobject);
 
688
 
 
689
  if (model->priv->temp_iter)
 
690
    {
 
691
      g_object_unref (model->priv->temp_iter);
 
692
      model->priv->temp_iter = NULL;
 
693
    }
 
694
 
 
695
  G_OBJECT_CLASS (clutter_list_model_parent_class)->dispose (gobject);
 
696
}
 
697
 
 
698
static void
 
699
clutter_list_model_class_init (ClutterListModelClass *klass)
 
700
{
 
701
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
702
  ClutterModelClass *model_class = CLUTTER_MODEL_CLASS (klass);
 
703
 
 
704
  gobject_class->finalize = clutter_list_model_finalize;
 
705
  gobject_class->dispose = clutter_list_model_dispose;
 
706
 
 
707
  model_class->get_iter_at_row = clutter_list_model_get_iter_at_row;
 
708
  model_class->insert_row = clutter_list_model_insert_row;
 
709
  model_class->remove_row = clutter_list_model_remove_row;
 
710
  model_class->resort = clutter_list_model_resort;
 
711
  model_class->get_n_rows = clutter_list_model_get_n_rows;
 
712
  model_class->row_removed = clutter_list_model_row_removed;
 
713
}
 
714
 
 
715
static void
 
716
clutter_list_model_init (ClutterListModel *model)
 
717
{
 
718
  model->priv = clutter_list_model_get_instance_private (model);
 
719
 
 
720
  model->priv->sequence = g_sequence_new (NULL);
 
721
  model->priv->temp_iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
 
722
                                         "model",
 
723
                                         model,
 
724
                                         NULL);
 
725
}
 
726
 
 
727
/**
 
728
 * clutter_list_model_new:
 
729
 * @n_columns: number of columns in the model
 
730
 * @...: @n_columns number of #GType and string pairs
 
731
 *
 
732
 * Creates a new default model with @n_columns columns with the types 
 
733
 * and names passed in.
 
734
 *
 
735
 * For example:
 
736
 * 
 
737
 * <informalexample><programlisting>
 
738
 * model = clutter_list_model_new (3,
 
739
 *                                 G_TYPE_INT,      "Score",
 
740
 *                                 G_TYPE_STRING,   "Team",
 
741
 *                                 GDK_TYPE_PIXBUF, "Logo");
 
742
 * </programlisting></informalexample>
 
743
 *
 
744
 * will create a new #ClutterModel with three columns of type int,
 
745
 * string and #GdkPixbuf respectively.
 
746
 *
 
747
 * Note that the name of the column can be set to %NULL, in which case
 
748
 * the canonical name of the type held by the column will be used as
 
749
 * the title.
 
750
 *
 
751
 * Return value: a new #ClutterListModel
 
752
 *
 
753
 * Since: 0.6
 
754
 *
 
755
 * Deprecated: 1.24: Use #GListStore instead
 
756
 */
 
757
ClutterModel *
 
758
clutter_list_model_new (guint n_columns,
 
759
                        ...)
 
760
{
 
761
  ClutterModel *model;
 
762
  va_list args;
 
763
  gint i;
 
764
 
 
765
  g_return_val_if_fail (n_columns > 0, NULL);
 
766
 
 
767
  model = g_object_new (CLUTTER_TYPE_LIST_MODEL, NULL);
 
768
  _clutter_model_set_n_columns (model, n_columns, TRUE, TRUE);
 
769
 
 
770
  va_start (args, n_columns);
 
771
 
 
772
  for (i = 0; i < n_columns; i++)
 
773
    { 
 
774
      GType type = va_arg (args, GType);
 
775
      const gchar *name = va_arg (args, gchar*);
 
776
 
 
777
      if (!_clutter_model_check_type (type))
 
778
        {
 
779
          g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
 
780
          g_object_unref (model);
 
781
          model = NULL;
 
782
          goto out;
 
783
        }
 
784
 
 
785
      _clutter_model_set_column_type (model, i, type);
 
786
      _clutter_model_set_column_name (model, i, name);
 
787
    }
 
788
 
 
789
 out:
 
790
  va_end (args);
 
791
  return model;
 
792
}
 
793
 
 
794
/**
 
795
 * clutter_list_model_newv:
 
796
 * @n_columns: number of columns in the model
 
797
 * @types: (array length=n_columns): an array of #GType types for the columns, from first to last
 
798
 * @names: (array length=n_columns): an array of names for the columns, from first to last
 
799
 *
 
800
 * Non-vararg version of clutter_list_model_new(). This function is
 
801
 * useful for language bindings.
 
802
 *
 
803
 * Return value: (transfer full): a new default #ClutterModel
 
804
 *
 
805
 * Since: 0.6
 
806
 *
 
807
 * Deprecated: 1.24: Use #GListStore instead
 
808
 */
 
809
ClutterModel *
 
810
clutter_list_model_newv (guint                n_columns,
 
811
                         GType               *types,
 
812
                         const gchar * const  names[])
 
813
{
 
814
  ClutterModel *model;
 
815
  gint i;
 
816
 
 
817
  g_return_val_if_fail (n_columns > 0, NULL);
 
818
 
 
819
  model = g_object_new (CLUTTER_TYPE_LIST_MODEL, NULL);
 
820
  _clutter_model_set_n_columns (model, n_columns, TRUE, TRUE);
 
821
 
 
822
  for (i = 0; i < n_columns; i++)
 
823
    {
 
824
      if (!_clutter_model_check_type (types[i]))
 
825
        {
 
826
          g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
 
827
          g_object_unref (model);
 
828
          return NULL;
 
829
        }
 
830
 
 
831
      _clutter_model_set_column_type (model, i, types[i]);
 
832
      _clutter_model_set_column_name (model, i, names[i]);
 
833
    }
 
834
 
 
835
  return model;
 
836
}