Implemented data-store using a casefile instead of an array of cases.
[pspp-builds.git] / src / ui / gui / psppire-case-file.c
1 /* 
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2006  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-file.h"
27
28 #include <gtksheet/gtkextra-marshal.h>
29
30 #include <data/case.h>
31 #include <data/casefile.h>
32 #include <data/data-in.h>
33
34 /* --- prototypes --- */
35 static void psppire_case_file_class_init        (PsppireCaseFileClass   *class);
36 static void psppire_case_file_init      (PsppireCaseFile        *case_file);
37 static void psppire_case_file_finalize  (GObject                *object);
38
39
40 /* --- variables --- */
41 static GObjectClass     *parent_class = NULL;
42
43 enum  {CASE_CHANGED, 
44        CASE_INSERTED,
45        CASES_DELETED,
46        n_SIGNALS};
47
48 static guint signal[n_SIGNALS];
49
50
51 /* --- functions --- */
52 /**
53  * psppire_case_file_get_type:
54  * @returns: the type ID for accelerator groups.
55  */
56 GType
57 psppire_case_file_get_type (void)
58 {
59   static GType object_type = 0;
60
61   if (!object_type)
62     {
63       static const GTypeInfo object_info = {
64         sizeof (PsppireCaseFileClass),
65         (GBaseInitFunc) NULL,
66         (GBaseFinalizeFunc) NULL,
67         (GClassInitFunc) psppire_case_file_class_init,
68         NULL,   /* class_finalize */
69         NULL,   /* class_data */
70         sizeof (PsppireCaseFile),
71         0,      /* n_preallocs */
72         (GInstanceInitFunc) psppire_case_file_init,
73       };
74
75       object_type = g_type_register_static (G_TYPE_PSPPIRE_OBJECT, "PsppireCaseFile",
76                                             &object_info, 0);
77     }
78
79   return object_type;
80 }
81
82
83 static void
84 psppire_case_file_class_init (PsppireCaseFileClass *class)
85 {
86   GObjectClass *object_class = G_OBJECT_CLASS (class);
87
88   parent_class = g_type_class_peek_parent (class);
89
90   object_class->finalize = psppire_case_file_finalize;
91
92   signal[CASE_CHANGED] =
93     g_signal_new ("case_changed",
94                   G_TYPE_FROM_CLASS(class),
95                   G_SIGNAL_RUN_FIRST,
96                   0,
97                   NULL, NULL,
98                   g_cclosure_marshal_VOID__INT,
99                   G_TYPE_NONE, 
100                   1,
101                   G_TYPE_INT);
102
103
104   signal[CASE_INSERTED] =
105     g_signal_new ("case_inserted",
106                   G_TYPE_FROM_CLASS(class),
107                   G_SIGNAL_RUN_FIRST,
108                   0,
109                   NULL, NULL,
110                   g_cclosure_marshal_VOID__INT,
111                   G_TYPE_NONE, 
112                   1,
113                   G_TYPE_INT);
114
115
116   signal[CASES_DELETED] =
117     g_signal_new ("cases_deleted",
118                   G_TYPE_FROM_CLASS(class),
119                   G_SIGNAL_RUN_FIRST,
120                   0,
121                   NULL, NULL,
122                   gtkextra_VOID__INT_INT,
123                   G_TYPE_NONE, 
124                   2,
125                   G_TYPE_INT, G_TYPE_INT);
126 }
127
128 static void
129 psppire_case_file_finalize (GObject *object)
130 {
131   PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
132   
133   if ( cf->casefile) 
134     casefile_destroy(cf->casefile);
135
136   G_OBJECT_CLASS (parent_class)->finalize (object);
137 }
138
139 static void
140 psppire_case_file_init (PsppireCaseFile *cf)
141 {
142   cf->casefile = 0;
143 }
144
145 /**
146  * psppire_case_file_new:
147  * @returns: a new #PsppireCaseFile object
148  * 
149  * Creates a new #PsppireCaseFile. 
150  */
151 PsppireCaseFile*
152 psppire_case_file_new (gint var_cnt)
153 {
154   PsppireCaseFile *cf = g_object_new (G_TYPE_PSPPIRE_CASE_FILE, NULL);
155
156   cf->casefile = casefile_create(var_cnt);
157
158   return cf;
159 }
160
161
162
163 /* Append a case to the case file */
164 gboolean
165 psppire_case_file_append_case(PsppireCaseFile *cf, 
166                               struct ccase *c)
167 {
168   bool result ;
169   gint posn ;
170
171   g_return_val_if_fail(cf, FALSE);
172   g_return_val_if_fail(cf->casefile, FALSE);
173
174   posn = casefile_get_case_cnt(cf->casefile);
175
176   result = casefile_append(cf->casefile, c);
177   
178   g_signal_emit(cf, signal[CASE_INSERTED], 0, posn);
179                 
180   return result;
181 }
182
183
184 inline gint
185 psppire_case_file_get_case_count(const PsppireCaseFile *cf)
186 {
187   g_return_val_if_fail(cf, FALSE);
188   
189   if ( ! cf->casefile) 
190     return 0;
191
192   return casefile_get_case_cnt(cf->casefile);
193 }
194
195 /* Return the IDXth value from case CASENUM.
196    The return value must not be freed or written to
197  */
198 const union value *
199 psppire_case_file_get_value(const PsppireCaseFile *cf, gint casenum, gint idx)
200 {
201   const union value *v; 
202   struct ccase c;
203   struct casereader *reader =  casefile_get_random_reader (cf->casefile);
204
205   casereader_seek(reader, casenum);
206
207   casereader_read(reader, &c);
208
209   v = case_data(&c, idx);
210   casereader_destroy(reader);
211   case_destroy(&c);
212
213   return v;
214 }
215
216 void
217 psppire_case_file_clear(PsppireCaseFile *cf)
218 {
219   casefile_destroy(cf->casefile);
220   cf->casefile = 0;
221   g_signal_emit(cf, signal[CASES_DELETED], 0, 0, -1);
222 }
223
224 /* Set the IDXth value of case C using FF and DATA */
225 gboolean
226 psppire_case_file_set_value(PsppireCaseFile *cf, gint casenum, gint idx,
227                             struct data_in *d_in)
228 {
229   struct ccase cc ;
230
231   struct casereader *reader =  casefile_get_random_reader (cf->casefile);
232
233   casereader_seek(reader, casenum);
234   casereader_read(reader, &cc);
235
236   /* Cast away const in flagrant abuse of the casefile */
237   d_in->v = (union value *) case_data(&cc, idx);
238
239   if ( ! data_in(d_in) ) 
240     g_warning("Cant set value\n");
241
242   case_destroy(&cc);
243   casereader_destroy(reader);
244
245   g_signal_emit(cf, signal[CASE_CHANGED], 0, casenum);
246
247   return TRUE;
248 }