Added new files resulting from directory restructuring.
[pspp-builds.git] / src / ui / gui / psppire-case-array.c
1 /* 
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2004  Free Software Foundation
4     Written by John Darrington
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19     02110-1301, USA. */
20
21
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "psppire-object.h"
26 #include "psppire-case-array.h"
27 #include "gtkextra-marshal.h"
28
29 #include "case.h"
30
31 /* --- prototypes --- */
32 static void psppire_case_array_class_init       (PsppireCaseArrayClass  *class);
33 static void psppire_case_array_init     (PsppireCaseArray       *case_array);
34 static void psppire_case_array_finalize (GObject                *object);
35
36
37 /* --- variables --- */
38 static GObjectClass     *parent_class = NULL;
39
40 enum  {CASE_CHANGED, 
41        CASE_INSERTED,
42        CASES_DELETED, 
43        n_SIGNALS};
44
45 static guint signal[n_SIGNALS];
46
47
48 /* --- functions --- */
49 /**
50  * psppire_case_array_get_type:
51  * @returns: the type ID for accelerator groups.
52  */
53 GType
54 psppire_case_array_get_type (void)
55 {
56   static GType object_type = 0;
57
58   if (!object_type)
59     {
60       static const GTypeInfo object_info = {
61         sizeof (PsppireCaseArrayClass),
62         (GBaseInitFunc) NULL,
63         (GBaseFinalizeFunc) NULL,
64         (GClassInitFunc) psppire_case_array_class_init,
65         NULL,   /* class_finalize */
66         NULL,   /* class_data */
67         sizeof (PsppireCaseArray),
68         0,      /* n_preallocs */
69         (GInstanceInitFunc) psppire_case_array_init,
70       };
71
72       object_type = g_type_register_static (G_TYPE_PSPPIRE_OBJECT, "PsppireCaseArray",
73                                             &object_info, 0);
74     }
75
76   return object_type;
77 }
78
79
80 static void
81 psppire_case_array_class_init (PsppireCaseArrayClass *class)
82 {
83   GObjectClass *object_class = G_OBJECT_CLASS (class);
84
85   parent_class = g_type_class_peek_parent (class);
86
87   object_class->finalize = psppire_case_array_finalize;
88
89   signal[CASE_CHANGED] =
90     g_signal_new ("case_changed",
91                   G_TYPE_FROM_CLASS(class),
92                   G_SIGNAL_RUN_FIRST,
93                   0,
94                   NULL, NULL,
95                   g_cclosure_marshal_VOID__INT,
96                   G_TYPE_NONE, 
97                   1,
98                   G_TYPE_INT);
99
100
101   signal[CASE_INSERTED] =
102     g_signal_new ("case_inserted",
103                   G_TYPE_FROM_CLASS(class),
104                   G_SIGNAL_RUN_FIRST,
105                   0,
106                   NULL, NULL,
107                   g_cclosure_marshal_VOID__INT,
108                   G_TYPE_NONE, 
109                   1,
110                   G_TYPE_INT);
111
112
113   signal[CASES_DELETED] =
114     g_signal_new ("cases_deleted",
115                   G_TYPE_FROM_CLASS(class),
116                   G_SIGNAL_RUN_FIRST,
117                   0,
118                   NULL, NULL,
119                   gtkextra_VOID__INT_INT,
120                   G_TYPE_NONE, 
121                   2,
122                   G_TYPE_INT,
123                   G_TYPE_INT);
124 }
125
126 static void
127 psppire_case_array_finalize (GObject *object)
128 {
129   PsppireCaseArray *ca = PSPPIRE_CASE_ARRAY (object);
130   
131   gint i;
132   for (i = 0 ; i < ca->size; ++i ) 
133     case_destroy(&ca->cases[i]);
134
135   g_free (ca->cases);
136
137   G_OBJECT_CLASS (parent_class)->finalize (object);
138 }
139
140 static void
141 psppire_case_array_init (PsppireCaseArray *ca)
142 {
143   ca->cases = 0;
144   ca->size = 0;
145 }
146
147 /**
148  * psppire_case_array_new:
149  * @returns: a new #PsppireCaseArray object
150  * 
151  * Creates a new #PsppireCaseArray. 
152  */
153 PsppireCaseArray*
154 psppire_case_array_new (gint capacity, gint width)
155 {
156   PsppireCaseArray *ca = g_object_new (G_TYPE_PSPPIRE_CASE_ARRAY, NULL);
157
158   ca->capacity = capacity;
159   ca->width = width;
160   
161   ca->cases = g_new0(struct ccase, capacity);
162
163   return ca;
164 }
165
166
167 void
168 psppire_case_array_resize(PsppireCaseArray *ca,  gint new_size)
169 {                      
170   gint c;
171
172   for (c = 0 ; c < ca->size ; ++c ) 
173     case_resize(&ca->cases[c], ca->width, new_size);
174   
175   ca->width = new_size;
176 }
177
178 /* FIXME: add_case and insert_case need to be merged/refactored */
179 gboolean
180 psppire_case_array_add_case(PsppireCaseArray *ca, 
181                          psppire_case_array_fill_case_func fill_case_func,
182                          gpointer aux)
183 {
184   g_return_val_if_fail(ca->size < ca->capacity, FALSE);
185
186   case_create(&ca->cases[ca->size], ca->width);
187
188   if ( !fill_case_func(&ca->cases[ca->size], aux))
189     return FALSE;
190
191   ca->size++;
192
193   g_signal_emit(ca, signal[CASE_INSERTED], 0, ca->size - 1);  
194
195   return TRUE;
196 }
197
198
199 gboolean
200 psppire_case_array_iterate_case(PsppireCaseArray *ca, 
201                          psppire_case_array_use_case_func use_case_func,
202                          gpointer aux)
203 {
204   gint i;
205   g_return_val_if_fail(ca->size < ca->capacity, FALSE);
206
207   for (i = 0 ; i < ca->size ; ++i ) 
208     {
209       if ( !use_case_func(&ca->cases[i], aux))
210         return FALSE;
211     }
212
213   return TRUE;
214 }
215
216
217 void
218 psppire_case_array_insert_case(PsppireCaseArray *ca, gint posn)
219 {
220   g_return_if_fail(posn >= 0);
221   g_return_if_fail(posn <= ca->size);
222
223   g_assert(ca->size + 1 <= ca->capacity);
224
225   gint i;
226
227   for(i = ca->size; i > posn ; --i)
228       case_move(&ca->cases[i], &ca->cases[i - 1]);
229
230   case_create(&ca->cases[posn], ca->width);
231
232   ca->size++;
233   g_signal_emit(ca, signal[CASE_INSERTED], 0, posn);
234 }
235
236 void
237 psppire_case_array_delete_cases(PsppireCaseArray *ca, gint first, gint n_cases)
238 {
239   g_return_if_fail(n_cases > 0);
240   g_return_if_fail(first >= 0);
241   g_return_if_fail(first + n_cases < ca->size);
242   
243   gint i;
244
245   /* FIXME: Is this right ?? */
246   for ( i = first; i < first + n_cases ; ++i ) 
247     case_destroy(&ca->cases[i]);
248
249   for ( ; i < ca->size; ++i ) 
250     case_move(&ca->cases[i - n_cases], &ca->cases[i]);
251
252   ca->size -= n_cases;
253   g_signal_emit(ca, signal[CASES_DELETED], 0, first, n_cases);  
254 }
255
256
257 gint
258 psppire_case_array_get_n_cases(const PsppireCaseArray *ca)
259 {
260   return ca->size;
261 }
262
263 /* Clears the contents of CA */
264 void 
265 psppire_case_array_clear(PsppireCaseArray *ca)
266 {
267   gint c;
268   for (c = 0 ; c < ca->size ; ++c ) 
269     case_destroy(&ca->cases[c]);
270
271   ca->size = 0;
272
273   g_signal_emit(ca, signal[CASES_DELETED], 0, 0, c);  
274 }
275
276 /* Return the IDXth value from case C */
277 const union value *
278 psppire_case_array_get_value(const PsppireCaseArray *ca, gint c, gint idx)
279 {
280   g_return_val_if_fail(c < ca->size, NULL);
281
282   return case_data(&ca->cases[c], idx);
283 }
284
285
286 /* Set the IDXth value of case C using FF and DATA */
287 void
288 psppire_case_array_set_value(PsppireCaseArray *ca, gint c, gint idx,
289                           value_fill_func_t ff,
290                           gpointer data)
291 {
292   g_return_if_fail(c < ca->size);
293
294   struct ccase *cc = &ca->cases[c];
295
296   union value *val = case_data_rw(cc, idx);
297
298   gboolean changed = ff(val, data);
299
300   case_unshare(cc);
301
302   if ( changed ) 
303     g_signal_emit(ca, signal[CASE_CHANGED], 0, c);
304   
305 }