No issues found
1 /*
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with the program; if not, see <http://www.gnu.org/licenses/>
15 *
16 *
17 * Authors:
18 * Chris Lahey <clahey@ximian.com>
19 * Miguel de Icaza <miguel@ximian.com>
20 *
21 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdlib.h>
30
31 #include "e-util/e-util.h"
32
33 #include "e-table-subset.h"
34
35 static void etss_proxy_model_pre_change_real
36 (ETableSubset *etss,
37 ETableModel *etm);
38 static void etss_proxy_model_no_change_real (ETableSubset *etss,
39 ETableModel *etm);
40 static void etss_proxy_model_changed_real (ETableSubset *etss,
41 ETableModel *etm);
42 static void etss_proxy_model_row_changed_real
43 (ETableSubset *etss,
44 ETableModel *etm,
45 gint row);
46 static void etss_proxy_model_cell_changed_real
47 (ETableSubset *etss,
48 ETableModel *etm,
49 gint col,
50 gint row);
51 static void etss_proxy_model_rows_inserted_real
52 (ETableSubset *etss,
53 ETableModel *etm,
54 gint row,
55 gint count);
56 static void etss_proxy_model_rows_deleted_real
57 (ETableSubset *etss,
58 ETableModel *etm,
59 gint row,
60 gint count);
61
62 #define d(x)
63
64 /* workaround for avoding API breakage */
65 #define etss_get_type e_table_subset_get_type
66 G_DEFINE_TYPE (ETableSubset, etss, E_TYPE_TABLE_MODEL)
67
68 #define ETSS_CLASS(object) (E_TABLE_SUBSET_GET_CLASS(object))
69
70 #define VALID_ROW(etss, row) (row >= -1 && row < etss->n_map)
71 #define MAP_ROW(etss, row) (row == -1 ? -1 : etss->map_table[row])
72
73 static gint
74 etss_get_view_row (ETableSubset *etss,
75 gint row)
76 {
77 const gint n = etss->n_map;
78 const gint * const map_table = etss->map_table;
79 gint i;
80
81 gint end = MIN (etss->n_map, etss->last_access + 10);
82 gint start = MAX (0, etss->last_access - 10);
83 gint initial = MAX (MIN (etss->last_access, end), start);
84
85 for (i = initial; i < end; i++) {
86 if (map_table[i] == row) {
87 d (g_print ("a) Found %d from %d\n", i, etss->last_access));
88 etss->last_access = i;
89 return i;
90 }
91 }
92
93 for (i = initial - 1; i >= start; i--) {
94 if (map_table[i] == row) {
95 d (g_print ("b) Found %d from %d\n", i, etss->last_access));
96 etss->last_access = i;
97 return i;
98 }
99 }
100
101 for (i = 0; i < n; i++) {
102 if (map_table[i] == row) {
103 d (g_print ("c) Found %d from %d\n", i, etss->last_access));
104 etss->last_access = i;
105 return i;
106 }
107 }
108 return -1;
109 }
110
111 static void
112 etss_dispose (GObject *object)
113 {
114 ETableSubset *etss = E_TABLE_SUBSET (object);
115
116 if (etss->source) {
117 g_signal_handler_disconnect (
118 etss->source,
119 etss->table_model_pre_change_id);
120 g_signal_handler_disconnect (
121 etss->source,
122 etss->table_model_no_change_id);
123 g_signal_handler_disconnect (
124 etss->source,
125 etss->table_model_changed_id);
126 g_signal_handler_disconnect (
127 etss->source,
128 etss->table_model_row_changed_id);
129 g_signal_handler_disconnect (
130 etss->source,
131 etss->table_model_cell_changed_id);
132 g_signal_handler_disconnect (
133 etss->source,
134 etss->table_model_rows_inserted_id);
135 g_signal_handler_disconnect (
136 etss->source,
137 etss->table_model_rows_deleted_id);
138
139 g_object_unref (etss->source);
140 etss->source = NULL;
141
142 etss->table_model_changed_id = 0;
143 etss->table_model_row_changed_id = 0;
144 etss->table_model_cell_changed_id = 0;
145 etss->table_model_rows_inserted_id = 0;
146 etss->table_model_rows_deleted_id = 0;
147 }
148
149 G_OBJECT_CLASS (etss_parent_class)->dispose (object);
150 }
151
152 static void
153 etss_finalize (GObject *object)
154 {
155 ETableSubset *etss = E_TABLE_SUBSET (object);
156
157 g_free (etss->map_table);
158 etss->map_table = NULL;
159
160 G_OBJECT_CLASS (etss_parent_class)->finalize (object);
161 }
162
163 static gint
164 etss_column_count (ETableModel *etm)
165 {
166 ETableSubset *etss = (ETableSubset *) etm;
167
168 return e_table_model_column_count (etss->source);
169 }
170
171 static gint
172 etss_row_count (ETableModel *etm)
173 {
174 ETableSubset *etss = (ETableSubset *) etm;
175
176 return etss->n_map;
177 }
178
179 static gpointer
180 etss_value_at (ETableModel *etm,
181 gint col,
182 gint row)
183 {
184 ETableSubset *etss = (ETableSubset *) etm;
185
186 g_return_val_if_fail (VALID_ROW (etss, row), NULL);
187
188 etss->last_access = row;
189 d (g_print ("g) Setting last_access to %d\n", row));
190 return e_table_model_value_at (etss->source, col, MAP_ROW (etss, row));
191 }
192
193 static void
194 etss_set_value_at (ETableModel *etm,
195 gint col,
196 gint row,
197 gconstpointer val)
198 {
199 ETableSubset *etss = (ETableSubset *) etm;
200
201 g_return_if_fail (VALID_ROW (etss, row));
202
203 etss->last_access = row;
204 d (g_print ("h) Setting last_access to %d\n", row));
205 e_table_model_set_value_at (etss->source, col, MAP_ROW (etss, row), val);
206 }
207
208 static gboolean
209 etss_is_cell_editable (ETableModel *etm,
210 gint col,
211 gint row)
212 {
213 ETableSubset *etss = (ETableSubset *) etm;
214
215 g_return_val_if_fail (VALID_ROW (etss, row), FALSE);
216
217 return e_table_model_is_cell_editable (etss->source, col, MAP_ROW (etss, row));
218 }
219
220 static gboolean
221 etss_has_save_id (ETableModel *etm)
222 {
223 return TRUE;
224 }
225
226 static gchar *
227 etss_get_save_id (ETableModel *etm,
228 gint row)
229 {
230 ETableSubset *etss = (ETableSubset *) etm;
231
232 g_return_val_if_fail (VALID_ROW (etss, row), NULL);
233
234 if (e_table_model_has_save_id (etss->source))
235 return e_table_model_get_save_id (etss->source, MAP_ROW (etss, row));
236 else
237 return g_strdup_printf ("%d", MAP_ROW (etss, row));
238 }
239
240 static void
241 etss_append_row (ETableModel *etm,
242 ETableModel *source,
243 gint row)
244 {
245 ETableSubset *etss = (ETableSubset *) etm;
246 e_table_model_append_row (etss->source, source, row);
247 }
248
249 static gpointer
250 etss_duplicate_value (ETableModel *etm,
251 gint col,
252 gconstpointer value)
253 {
254 ETableSubset *etss = (ETableSubset *) etm;
255
256 return e_table_model_duplicate_value (etss->source, col, value);
257 }
258
259 static void
260 etss_free_value (ETableModel *etm,
261 gint col,
262 gpointer value)
263 {
264 ETableSubset *etss = (ETableSubset *) etm;
265
266 e_table_model_free_value (etss->source, col, value);
267 }
268
269 static gpointer
270 etss_initialize_value (ETableModel *etm,
271 gint col)
272 {
273 ETableSubset *etss = (ETableSubset *) etm;
274
275 return e_table_model_initialize_value (etss->source, col);
276 }
277
278 static gboolean
279 etss_value_is_empty (ETableModel *etm,
280 gint col,
281 gconstpointer value)
282 {
283 ETableSubset *etss = (ETableSubset *) etm;
284
285 return e_table_model_value_is_empty (etss->source, col, value);
286 }
287
288 static gchar *
289 etss_value_to_string (ETableModel *etm,
290 gint col,
291 gconstpointer value)
292 {
293 ETableSubset *etss = (ETableSubset *) etm;
294
295 return e_table_model_value_to_string (etss->source, col, value);
296 }
297
298 static void
299 etss_class_init (ETableSubsetClass *class)
300 {
301 ETableModelClass *table_class = E_TABLE_MODEL_CLASS (class);
302 GObjectClass *object_class = G_OBJECT_CLASS (class);
303
304 object_class->dispose = etss_dispose;
305 object_class->finalize = etss_finalize;
306
307 table_class->column_count = etss_column_count;
308 table_class->row_count = etss_row_count;
309 table_class->append_row = etss_append_row;
310
311 table_class->value_at = etss_value_at;
312 table_class->set_value_at = etss_set_value_at;
313 table_class->is_cell_editable = etss_is_cell_editable;
314
315 table_class->has_save_id = etss_has_save_id;
316 table_class->get_save_id = etss_get_save_id;
317
318 table_class->duplicate_value = etss_duplicate_value;
319 table_class->free_value = etss_free_value;
320 table_class->initialize_value = etss_initialize_value;
321 table_class->value_is_empty = etss_value_is_empty;
322 table_class->value_to_string = etss_value_to_string;
323
324 class->proxy_model_pre_change = etss_proxy_model_pre_change_real;
325 class->proxy_model_no_change = etss_proxy_model_no_change_real;
326 class->proxy_model_changed = etss_proxy_model_changed_real;
327 class->proxy_model_row_changed = etss_proxy_model_row_changed_real;
328 class->proxy_model_cell_changed = etss_proxy_model_cell_changed_real;
329 class->proxy_model_rows_inserted = etss_proxy_model_rows_inserted_real;
330 class->proxy_model_rows_deleted = etss_proxy_model_rows_deleted_real;
331 }
332
333 static void
334 etss_init (ETableSubset *etss)
335 {
336 etss->last_access = 0;
337 }
338
339 static void
340 etss_proxy_model_pre_change_real (ETableSubset *etss,
341 ETableModel *etm)
342 {
343 e_table_model_pre_change (E_TABLE_MODEL (etss));
344 }
345
346 static void
347 etss_proxy_model_no_change_real (ETableSubset *etss,
348 ETableModel *etm)
349 {
350 e_table_model_no_change (E_TABLE_MODEL (etss));
351 }
352
353 static void
354 etss_proxy_model_changed_real (ETableSubset *etss,
355 ETableModel *etm)
356 {
357 e_table_model_changed (E_TABLE_MODEL (etss));
358 }
359
360 static void
361 etss_proxy_model_row_changed_real (ETableSubset *etss,
362 ETableModel *etm,
363 gint row)
364 {
365 gint view_row = etss_get_view_row (etss, row);
366 if (view_row != -1)
367 e_table_model_row_changed (E_TABLE_MODEL (etss), view_row);
368 else
369 e_table_model_no_change (E_TABLE_MODEL (etss));
370 }
371
372 static void
373 etss_proxy_model_cell_changed_real (ETableSubset *etss,
374 ETableModel *etm,
375 gint col,
376 gint row)
377 {
378 gint view_row = etss_get_view_row (etss, row);
379 if (view_row != -1)
380 e_table_model_cell_changed (E_TABLE_MODEL (etss), col, view_row);
381 else
382 e_table_model_no_change (E_TABLE_MODEL (etss));
383 }
384
385 static void
386 etss_proxy_model_rows_inserted_real (ETableSubset *etss,
387 ETableModel *etm,
388 gint row,
389 gint count)
390 {
391 e_table_model_no_change (E_TABLE_MODEL (etss));
392 }
393
394 static void
395 etss_proxy_model_rows_deleted_real (ETableSubset *etss,
396 ETableModel *etm,
397 gint row,
398 gint count)
399 {
400 e_table_model_no_change (E_TABLE_MODEL (etss));
401 }
402
403 static void
404 etss_proxy_model_pre_change (ETableModel *etm,
405 ETableSubset *etss)
406 {
407 if (ETSS_CLASS (etss)->proxy_model_pre_change)
408 (ETSS_CLASS (etss)->proxy_model_pre_change) (etss, etm);
409 }
410
411 static void
412 etss_proxy_model_no_change (ETableModel *etm,
413 ETableSubset *etss)
414 {
415 if (ETSS_CLASS (etss)->proxy_model_no_change)
416 (ETSS_CLASS (etss)->proxy_model_no_change) (etss, etm);
417 }
418
419 static void
420 etss_proxy_model_changed (ETableModel *etm,
421 ETableSubset *etss)
422 {
423 if (ETSS_CLASS (etss)->proxy_model_changed)
424 (ETSS_CLASS (etss)->proxy_model_changed) (etss, etm);
425 }
426
427 static void
428 etss_proxy_model_row_changed (ETableModel *etm,
429 gint row,
430 ETableSubset *etss)
431 {
432 if (ETSS_CLASS (etss)->proxy_model_row_changed)
433 (ETSS_CLASS (etss)->proxy_model_row_changed) (etss, etm, row);
434 }
435
436 static void
437 etss_proxy_model_cell_changed (ETableModel *etm,
438 gint col,
439 gint row,
440 ETableSubset *etss)
441 {
442 if (ETSS_CLASS (etss)->proxy_model_cell_changed)
443 (ETSS_CLASS (etss)->proxy_model_cell_changed) (etss, etm, col, row);
444 }
445
446 static void
447 etss_proxy_model_rows_inserted (ETableModel *etm,
448 gint row,
449 gint col,
450 ETableSubset *etss)
451 {
452 if (ETSS_CLASS (etss)->proxy_model_rows_inserted)
453 (ETSS_CLASS (etss)->proxy_model_rows_inserted) (etss, etm, row, col);
454 }
455
456 static void
457 etss_proxy_model_rows_deleted (ETableModel *etm,
458 gint row,
459 gint col,
460 ETableSubset *etss)
461 {
462 if (ETSS_CLASS (etss)->proxy_model_rows_deleted)
463 (ETSS_CLASS (etss)->proxy_model_rows_deleted) (etss, etm, row, col);
464 }
465
466 ETableModel *
467 e_table_subset_construct (ETableSubset *etss,
468 ETableModel *source,
469 gint nvals)
470 {
471 guint *buffer;
472 gint i;
473
474 if (nvals) {
475 buffer = (guint *) g_malloc (sizeof (guint) * nvals);
476 if (buffer == NULL)
477 return NULL;
478 } else
479 buffer = NULL;
480 etss->map_table = (gint *) buffer;
481 etss->n_map = nvals;
482 etss->source = source;
483 g_object_ref (source);
484
485 /* Init */
486 for (i = 0; i < nvals; i++)
487 etss->map_table[i] = i;
488
489 etss->table_model_pre_change_id = g_signal_connect (
490 source, "model_pre_change",
491 G_CALLBACK (etss_proxy_model_pre_change), etss);
492 etss->table_model_no_change_id = g_signal_connect (
493 source, "model_no_change",
494 G_CALLBACK (etss_proxy_model_no_change), etss);
495 etss->table_model_changed_id = g_signal_connect (
496 source, "model_changed",
497 G_CALLBACK (etss_proxy_model_changed), etss);
498 etss->table_model_row_changed_id = g_signal_connect (
499 source, "model_row_changed",
500 G_CALLBACK (etss_proxy_model_row_changed), etss);
501 etss->table_model_cell_changed_id = g_signal_connect (
502 source, "model_cell_changed",
503 G_CALLBACK (etss_proxy_model_cell_changed), etss);
504 etss->table_model_rows_inserted_id = g_signal_connect (
505 source, "model_rows_inserted",
506 G_CALLBACK (etss_proxy_model_rows_inserted), etss);
507 etss->table_model_rows_deleted_id = g_signal_connect (
508 source, "model_rows_deleted",
509 G_CALLBACK (etss_proxy_model_rows_deleted), etss);
510
511 return E_TABLE_MODEL (etss);
512 }
513
514 ETableModel *
515 e_table_subset_new (ETableModel *source,
516 const gint nvals)
517 {
518 ETableSubset *etss = g_object_new (E_TYPE_TABLE_SUBSET, NULL);
519
520 if (e_table_subset_construct (etss, source, nvals) == NULL) {
521 g_object_unref (etss);
522 return NULL;
523 }
524
525 return (ETableModel *) etss;
526 }
527
528 gint
529 e_table_subset_model_to_view_row (ETableSubset *ets,
530 gint model_row)
531 {
532 gint i;
533 for (i = 0; i < ets->n_map; i++) {
534 if (ets->map_table[i] == model_row)
535 return i;
536 }
537 return -1;
538 }
539
540 gint
541 e_table_subset_view_to_model_row (ETableSubset *ets,
542 gint view_row)
543 {
544 if (view_row >= 0 && view_row < ets->n_map)
545 return ets->map_table[view_row];
546 else
547 return -1;
548 }
549
550 ETableModel *
551 e_table_subset_get_toplevel (ETableSubset *table)
552 {
553 g_return_val_if_fail (table != NULL, NULL);
554 g_return_val_if_fail (E_IS_TABLE_SUBSET (table), NULL);
555
556 if (E_IS_TABLE_SUBSET (table->source))
557 return e_table_subset_get_toplevel (E_TABLE_SUBSET (table->source));
558 else
559 return table->source;
560 }
561
562 void
563 e_table_subset_print_debugging (ETableSubset *table_model)
564 {
565 gint i;
566 for (i = 0; i < table_model->n_map; i++) {
567 g_print ("%8d\n", table_model->map_table[i]);
568 }
569 }