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 *
20 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <gtk/gtk.h>
29
30 #include "e-bit-array.h"
31 #include "e-util.h"
32
33 #define ONES ((guint32) 0xffffffff)
34
35 #define BOX(n) ((n) / 32)
36 #define OFFSET(n) (31 - ((n) % 32))
37 #define BITMASK(n) ((guint32)(((guint32) 0x1) << OFFSET((n))))
38 #define BITMASK_LEFT(n) ((((n) % 32) == 0) ? 0 : (ONES << (32 - ((n) % 32))))
39 #define BITMASK_RIGHT(n) ((guint32)(((guint32) ONES) >> ((n) % 32)))
40
41 G_DEFINE_TYPE (
42 EBitArray,
43 e_bit_array,
44 G_TYPE_OBJECT)
45
46 static void
47 e_bit_array_insert_real (EBitArray *eba,
48 gint row)
49 {
50 gint box;
51 gint i;
52 if (eba->bit_count >= 0) {
53 /* Add another word if needed. */
54 if ((eba->bit_count & 0x1f) == 0) {
55 eba->data = g_renew (
56 guint32, eba->data,
57 (eba->bit_count >> 5) + 1);
58 eba->data[eba->bit_count >> 5] = 0;
59 }
60
61 /* The box is the word that our row is in. */
62 box = BOX (row);
63 /* Shift all words to the right of our box right one bit. */
64 for (i = eba->bit_count >> 5; i > box; i--) {
65 eba->data[i] = (eba->data[i] >> 1) | (eba->data[i - 1] << 31);
66 }
67
68 /* Shift right half of box one bit to the right. */
69 eba->data[box] =
70 (eba->data[box] & BITMASK_LEFT (row)) |
71 ((eba->data[box] & BITMASK_RIGHT (row)) >> 1);
72 eba->bit_count++;
73 }
74 }
75
76 static void
77 e_bit_array_delete_real (EBitArray *eba,
78 gint row,
79 gboolean move_selection_mode)
80 {
81 gint box;
82 gint i;
83 gint last;
84 gint selected = FALSE;
85
86 if (eba->bit_count > 0) {
87 guint32 bitmask;
88 box = row >> 5;
89 last = (eba->bit_count - 1) >> 5;
90
91 /* Build bitmasks for the left and right half of the box */
92 bitmask = BITMASK_RIGHT (row) >> 1;
93 if (move_selection_mode)
94 selected = e_bit_array_value_at (eba, row);
95 /* Shift right half of box one bit to the left. */
96 eba->data[box] =
97 (eba->data[box] & BITMASK_LEFT (row)) |
98 ((eba->data[box] & bitmask) << 1);
99
100 /* Shift all words to the right of our box left one bit. */
101 if (box < last) {
102 eba->data[box] &= eba->data[box + 1] >> 31;
103
104 for (i = box + 1; i < last; i++) {
105 eba->data[i] =
106 (eba->data[i] << 1) |
107 (eba->data[i + 1] >> 31);
108 }
109 /* this over-runs our memory! */
110 /*eba->data[i] = eba->data[i] << 1; */
111 }
112 eba->bit_count--;
113 /* Remove the last word if not needed. */
114 if ((eba->bit_count & 0x1f) == 0) {
115 eba->data = g_renew (guint32, eba->data, eba->bit_count >> 5);
116 }
117 if (move_selection_mode && selected && eba->bit_count > 0) {
118 e_bit_array_select_single_row (
119 eba, row == eba->bit_count ? row - 1 : row);
120 }
121 }
122 }
123
124 /* FIXME : Improve efficiency here. */
125 void
126 e_bit_array_delete (EBitArray *eba,
127 gint row,
128 gint count)
129 {
130 gint i;
131 for (i = 0; i < count; i++)
132 e_bit_array_delete_real (eba, row, FALSE);
133 }
134
135 /* FIXME : Improve efficiency here. */
136 void
137 e_bit_array_delete_single_mode (EBitArray *eba,
138 gint row,
139 gint count)
140 {
141 gint i;
142 for (i = 0; i < count; i++)
143 e_bit_array_delete_real (eba, row, TRUE);
144 }
145
146 /* FIXME : Improve efficiency here. */
147 void
148 e_bit_array_insert (EBitArray *eba,
149 gint row,
150 gint count)
151 {
152 gint i;
153 for (i = 0; i < count; i++)
154 e_bit_array_insert_real (eba, row);
155 }
156
157 /* FIXME: Implement this more efficiently. */
158 void
159 e_bit_array_move_row (EBitArray *eba,
160 gint old_row,
161 gint new_row)
162 {
163 e_bit_array_delete_real (eba, old_row, FALSE);
164 e_bit_array_insert_real (eba, new_row);
165 }
166
167 static void
168 eba_dispose (GObject *object)
169 {
170 EBitArray *eba;
171
172 eba = E_BIT_ARRAY (object);
173
174 if (eba->data)
175 g_free (eba->data);
176 eba->data = NULL;
177
178 /* Chain up to parent's dispose() method. */
179 G_OBJECT_CLASS (e_bit_array_parent_class)->dispose (object);
180 }
181
182 /**
183 * e_selection_model_is_row_selected
184 * @selection: #EBitArray to check
185 * @n: The row to check
186 *
187 * This routine calculates whether the given row is selected.
188 *
189 * Returns: %TRUE if the given row is selected
190 */
191 gboolean
192 e_bit_array_value_at (EBitArray *eba,
193 gint n)
194 {
195 if (eba->bit_count < n || eba->bit_count == 0)
196 return 0;
197 else
198 return (eba->data[BOX (n)] >> OFFSET (n)) & 0x1;
199 }
200
201 /**
202 * e_selection_model_foreach
203 * @selection: #EBitArray to traverse
204 * @callback: The callback function to call back.
205 * @closure: The closure
206 *
207 * This routine calls the given callback function once for each
208 * selected row, passing closure as the closure.
209 */
210 void
211 e_bit_array_foreach (EBitArray *eba,
212 EForeachFunc callback,
213 gpointer closure)
214 {
215 gint i;
216 gint last = (eba->bit_count + 31) / 32;
217 for (i = 0; i < last; i++) {
218 if (eba->data[i]) {
219 gint j;
220 guint32 value = eba->data[i];
221 for (j = 0; j < 32; j++) {
222 if (value & 0x80000000) {
223 callback (i * 32 + j, closure);
224 }
225 value <<= 1;
226 }
227 }
228 }
229 }
230
231 #define PART(x,n) (((x) & (0x01010101 << n)) >> n)
232 #define SECTION(x, n) (((x) >> (n * 8)) & 0xff)
233
234 /**
235 * e_selection_model_selected_count
236 * @selection: #EBitArray to count
237 *
238 * This routine calculates the number of rows selected.
239 *
240 * Returns: The number of rows selected in the given model.
241 */
242 gint
243 e_bit_array_selected_count (EBitArray *eba)
244 {
245 gint count;
246 gint i;
247 gint last;
248
249 if (!eba->data)
250 return 0;
251
252 count = 0;
253
254 last = BOX (eba->bit_count - 1);
255
256 for (i = 0; i <= last; i++) {
257 gint j;
258 guint32 thiscount = 0;
259 for (j = 0; j < 8; j++)
260 thiscount += PART (eba->data[i], j);
261 for (j = 0; j < 4; j++)
262 count += SECTION (thiscount, j);
263 }
264
265 return count;
266 }
267
268 /**
269 * e_selection_model_select_all
270 * @selection: #EBitArray to select all
271 *
272 * This routine selects all the rows in the given
273 * #EBitArray.
274 */
275 void
276 e_bit_array_select_all (EBitArray *eba)
277 {
278 gint i;
279
280 if (!eba->data)
281 eba->data = g_new0 (guint32, (eba->bit_count + 31) / 32);
282
283 for (i = 0; i < (eba->bit_count + 31) / 32; i++) {
284 eba->data[i] = ONES;
285 }
286
287 /* need to zero out the bits corresponding to the rows not
288 * selected in the last full 32 bit mask */
289 if (eba->bit_count % 32) {
290 gint unselected_mask = 0;
291 gint num_unselected_in_last_byte = 32 - eba->bit_count % 32;
292
293 for (i = 0; i < num_unselected_in_last_byte; i++)
294 unselected_mask |= 1 << i;
295
296 eba->data[(eba->bit_count + 31) / 32 - 1] &= ~unselected_mask;
297 }
298 }
299
300 /**
301 * e_selection_model_invert_selection
302 * @selection: #EBitArray to invert
303 *
304 * This routine inverts all the rows in the given
305 * #EBitArray.
306 */
307 void
308 e_bit_array_invert_selection (EBitArray *eba)
309 {
310 gint i;
311
312 if (!eba->data)
313 eba->data = g_new0 (guint32, (eba->bit_count + 31) / 32);
314
315 for (i = 0; i < (eba->bit_count + 31) / 32; i++) {
316 eba->data[i] = ~eba->data[i];
317 }
318 }
319
320 gint
321 e_bit_array_bit_count (EBitArray *eba)
322 {
323 return eba->bit_count;
324 }
325
326 #define OPERATE(object, i,mask,grow) \
327 ((grow) ? (((object)->data[(i)]) |= ((guint32) ~(mask))) : \
328 (((object)->data[(i)]) &= (mask)))
329
330 void
331 e_bit_array_change_one_row (EBitArray *eba,
332 gint row,
333 gboolean grow)
334 {
335 gint i;
336 i = BOX (row);
337
338 OPERATE (eba, i, ~BITMASK (row), grow);
339 }
340
341 void
342 e_bit_array_change_range (EBitArray *eba,
343 gint start,
344 gint end,
345 gboolean grow)
346 {
347 gint i, last;
348 if (start != end) {
349 i = BOX (start);
350 last = BOX (end);
351
352 if (i == last) {
353 OPERATE (
354 eba, i, BITMASK_LEFT (start) |
355 BITMASK_RIGHT (end), grow);
356 } else {
357 OPERATE (eba, i, BITMASK_LEFT (start), grow);
358 if (grow)
359 for (i++; i < last; i++)
360 eba->data[i] = ONES;
361 else
362 for (i++; i < last; i++)
363 eba->data[i] = 0;
364 OPERATE (eba, i, BITMASK_RIGHT (end), grow);
365 }
366 }
367 }
368
369 void
370 e_bit_array_select_single_row (EBitArray *eba,
371 gint row)
372 {
373 gint i;
374 for (i = 0; i < ((eba->bit_count + 31) / 32); i++) {
375 if (!((i == BOX (row) && eba->data[i] == BITMASK (row)) ||
376 (i != BOX (row) && eba->data[i] == 0))) {
377 g_free (eba->data);
378 eba->data = g_new0 (guint32, (eba->bit_count + 31) / 32);
379 eba->data[BOX (row)] = BITMASK (row);
380
381 break;
382 }
383 }
384 }
385
386 void
387 e_bit_array_toggle_single_row (EBitArray *eba,
388 gint row)
389 {
390 if (eba->data[BOX (row)] & BITMASK (row))
391 eba->data[BOX (row)] &= ~BITMASK (row);
392 else
393 eba->data[BOX (row)] |= BITMASK (row);
394 }
395
396 static void
397 e_bit_array_init (EBitArray *eba)
398 {
399 eba->data = NULL;
400 eba->bit_count = 0;
401 }
402
403 static void
404 e_bit_array_class_init (EBitArrayClass *class)
405 {
406 GObjectClass *object_class;
407
408 object_class = G_OBJECT_CLASS (class);
409
410 object_class->dispose = eba_dispose;
411 }
412
413 EBitArray *
414 e_bit_array_new (gint count)
415 {
416 EBitArray *eba = g_object_new (E_BIT_ARRAY_TYPE, NULL);
417 eba->bit_count = count;
418 eba->data = g_new0 (guint32, (eba->bit_count + 31) / 32);
419 return eba;
420 }