No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Chris Lahey <clahey@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "e-util/e-util.h"
31
32 #include "e-table-sorted-variable.h"
33 #include "e-table-sorting-utils.h"
34
35 #define d(x)
36
37 #define INCREMENT_AMOUNT 100
38
39 /* maximum insertions between an idle event that we will do without scheduling an idle sort */
40 #define ETSV_INSERT_MAX (4)
41
42 /* workaround for avoiding API breakage */
43 #define etsv_get_type e_table_sorted_variable_get_type
44 G_DEFINE_TYPE (ETableSortedVariable, etsv, E_TYPE_TABLE_SUBSET_VARIABLE)
45
46 static void etsv_sort_info_changed (ETableSortInfo *info, ETableSortedVariable *etsv);
47 static void etsv_sort (ETableSortedVariable *etsv);
48 static void etsv_add (ETableSubsetVariable *etssv, gint row);
49 static void etsv_add_all (ETableSubsetVariable *etssv);
50
51 static void
52 etsv_dispose (GObject *object)
53 {
54 ETableSortedVariable *etsv = E_TABLE_SORTED_VARIABLE (object);
55
56 if (etsv->sort_info_changed_id)
57 g_signal_handler_disconnect (
58 etsv->sort_info,
59 etsv->sort_info_changed_id);
60 etsv->sort_info_changed_id = 0;
61
62 if (etsv->sort_idle_id) {
63 g_source_remove (etsv->sort_idle_id);
64 etsv->sort_idle_id = 0;
65 }
66 if (etsv->insert_idle_id) {
67 g_source_remove (etsv->insert_idle_id);
68 etsv->insert_idle_id = 0;
69 }
70
71 if (etsv->sort_info)
72 g_object_unref (etsv->sort_info);
73 etsv->sort_info = NULL;
74
75 if (etsv->full_header)
76 g_object_unref (etsv->full_header);
77 etsv->full_header = NULL;
78
79 G_OBJECT_CLASS (etsv_parent_class)->dispose (object);
80 }
81
82 static void
83 etsv_class_init (ETableSortedVariableClass *class)
84 {
85 ETableSubsetVariableClass *etssv_class = E_TABLE_SUBSET_VARIABLE_CLASS (class);
86 GObjectClass *object_class = G_OBJECT_CLASS (class);
87
88 object_class->dispose = etsv_dispose;
89
90 etssv_class->add = etsv_add;
91 etssv_class->add_all = etsv_add_all;
92 }
93
94 static void
95 etsv_init (ETableSortedVariable *etsv)
96 {
97 etsv->full_header = NULL;
98 etsv->sort_info = NULL;
99
100 etsv->sort_info_changed_id = 0;
101
102 etsv->sort_idle_id = 0;
103 etsv->insert_count = 0;
104 }
105
106 static gboolean
107 etsv_sort_idle (ETableSortedVariable *etsv)
108 {
109 g_object_ref (etsv);
110 etsv_sort (etsv);
111 etsv->sort_idle_id = 0;
112 etsv->insert_count = 0;
113 g_object_unref (etsv);
114 return FALSE;
115 }
116
117 static gboolean
118 etsv_insert_idle (ETableSortedVariable *etsv)
119 {
120 etsv->insert_count = 0;
121 etsv->insert_idle_id = 0;
122 return FALSE;
123 }
124
125 static void
126 etsv_add (ETableSubsetVariable *etssv,
127 gint row)
128 {
129 ETableModel *etm = E_TABLE_MODEL (etssv);
130 ETableSubset *etss = E_TABLE_SUBSET (etssv);
131 ETableSortedVariable *etsv = E_TABLE_SORTED_VARIABLE (etssv);
132 gint i;
133
134 e_table_model_pre_change (etm);
135
136 if (etss->n_map + 1 > etssv->n_vals_allocated) {
137 etssv->n_vals_allocated += INCREMENT_AMOUNT;
138 etss->map_table = g_realloc (etss->map_table, (etssv->n_vals_allocated) * sizeof (gint));
139 }
140 i = etss->n_map;
141 if (etsv->sort_idle_id == 0) {
142 /* this is to see if we're inserting a lot of things between idle loops.
143 * If we are, we're busy, its faster to just append and perform a full sort later */
144 etsv->insert_count++;
145 if (etsv->insert_count > ETSV_INSERT_MAX) {
146 /* schedule a sort, and append instead */
147 etsv->sort_idle_id = g_idle_add_full (50, (GSourceFunc) etsv_sort_idle, etsv, NULL);
148 } else {
149 /* make sure we have an idle handler to reset the count every now and then */
150 if (etsv->insert_idle_id == 0) {
151 etsv->insert_idle_id = g_idle_add_full (40, (GSourceFunc) etsv_insert_idle, etsv, NULL);
152 }
153 i = e_table_sorting_utils_insert (etss->source, etsv->sort_info, etsv->full_header, etss->map_table, etss->n_map, row);
154 memmove (etss->map_table + i + 1, etss->map_table + i, (etss->n_map - i) * sizeof (gint));
155 }
156 }
157 etss->map_table[i] = row;
158 etss->n_map++;
159
160 e_table_model_row_inserted (etm, i);
161 }
162
163 static void
164 etsv_add_all (ETableSubsetVariable *etssv)
165 {
166 ETableModel *etm = E_TABLE_MODEL (etssv);
167 ETableSubset *etss = E_TABLE_SUBSET (etssv);
168 ETableSortedVariable *etsv = E_TABLE_SORTED_VARIABLE (etssv);
169 gint rows;
170 gint i;
171
172 e_table_model_pre_change (etm);
173
174 rows = e_table_model_row_count (etss->source);
175
176 if (etss->n_map + rows > etssv->n_vals_allocated) {
177 etssv->n_vals_allocated += MAX (INCREMENT_AMOUNT, rows);
178 etss->map_table = g_realloc (etss->map_table, etssv->n_vals_allocated * sizeof (gint));
179 }
180 for (i = 0; i < rows; i++)
181 etss->map_table[etss->n_map++] = i;
182
183 if (etsv->sort_idle_id == 0) {
184 etsv->sort_idle_id = g_idle_add_full (50, (GSourceFunc) etsv_sort_idle, etsv, NULL);
185 }
186
187 e_table_model_changed (etm);
188 }
189
190 ETableModel *
191 e_table_sorted_variable_new (ETableModel *source,
192 ETableHeader *full_header,
193 ETableSortInfo *sort_info)
194 {
195 ETableSortedVariable *etsv = g_object_new (E_TYPE_TABLE_SORTED_VARIABLE, NULL);
196 ETableSubsetVariable *etssv = E_TABLE_SUBSET_VARIABLE (etsv);
197
198 if (e_table_subset_variable_construct (etssv, source) == NULL) {
199 g_object_unref (etsv);
200 return NULL;
201 }
202
203 etsv->sort_info = sort_info;
204 g_object_ref (etsv->sort_info);
205 etsv->full_header = full_header;
206 g_object_ref (etsv->full_header);
207
208 etsv->sort_info_changed_id = g_signal_connect (
209 sort_info, "sort_info_changed",
210 G_CALLBACK (etsv_sort_info_changed), etsv);
211
212 return E_TABLE_MODEL (etsv);
213 }
214
215 static void
216 etsv_sort_info_changed (ETableSortInfo *info,
217 ETableSortedVariable *etsv)
218 {
219 etsv_sort (etsv);
220 }
221
222 static void
223 etsv_sort (ETableSortedVariable *etsv)
224 {
225 ETableSubset *etss = E_TABLE_SUBSET (etsv);
226 static gint reentering = 0;
227 if (reentering)
228 return;
229 reentering = 1;
230
231 e_table_model_pre_change (E_TABLE_MODEL (etsv));
232
233 e_table_sorting_utils_sort (etss->source, etsv->sort_info, etsv->full_header, etss->map_table, etss->n_map);
234
235 e_table_model_changed (E_TABLE_MODEL (etsv));
236 reentering = 0;
237 }