Implement DATASET commands.
[pspp-builds.git] / src / ui / gui / executor.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007, 2009, 2010, 2011  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "ui/gui/executor.h"
20
21 #include "data/dataset.h"
22 #include "data/lazy-casereader.h"
23 #include "data/session.h"
24 #include "language/command.h"
25 #include "language/lexer/lexer.h"
26 #include "libpspp/cast.h"
27 #include "output/driver.h"
28 #include "ui/gui/psppire-data-store.h"
29 #include "ui/gui/psppire-output-window.h"
30
31 /* Lazy casereader callback function used by execute_syntax. */
32 static struct casereader *
33 create_casereader_from_data_store (void *data_store_)
34 {
35   PsppireDataStore *data_store = data_store_;
36   return psppire_data_store_get_reader (data_store);
37 }
38
39 static void
40 new_pdw_cb (struct dataset *ds, void *aux UNUSED)
41 {
42   PsppireDataWindow *pdw = psppire_data_window_for_dataset (ds);
43   if (pdw == NULL)
44     pdw = PSPPIRE_DATA_WINDOW (psppire_data_window_new (ds));
45
46   switch (dataset_get_display (ds))
47     {
48     case DATASET_ASIS:
49       break;
50
51     case DATASET_FRONT:
52       gtk_widget_show (GTK_WIDGET (pdw));
53       gtk_window_deiconify (GTK_WINDOW (pdw));
54       gdk_window_raise (gtk_widget_get_window (GTK_WIDGET (pdw)));
55       psppire_data_window_set_default (pdw);
56       break;
57
58     case DATASET_MINIMIZED:
59       gtk_window_iconify (GTK_WINDOW (pdw));
60       gtk_widget_show (GTK_WIDGET (pdw));
61       psppire_data_window_undefault (pdw);
62       break;
63
64     case DATASET_HIDDEN:
65       gtk_widget_hide (GTK_WIDGET (pdw));
66       psppire_data_window_undefault (pdw);
67       break;
68     }
69   dataset_set_display (ds, DATASET_ASIS);
70 }
71
72 gboolean
73 execute_syntax (PsppireDataWindow *window, struct lex_reader *lex_reader)
74 {
75   struct lexer *lexer;
76   gboolean retval = TRUE;
77
78   PsppireDataWindow *pdw, *next_pdw;
79
80   ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
81     {
82       const struct caseproto *proto;
83       struct casereader *reader;
84       casenumber case_cnt;
85
86       /* When the user executes a number of snippets of syntax in a
87          row, none of which read from the active dataset, the GUI becomes
88          progressively less responsive.  The reason is that each syntax
89          execution encapsulates the active dataset data in another
90          datasheet layer.  The cumulative effect of having a number of
91          layers of datasheets wastes time and space.
92
93          To solve the problem, we use a "lazy casereader", a wrapper
94          around the casereader obtained from the data store, that
95          only actually instantiates that casereader when it is
96          needed.  If the data store casereader is never needed, then
97          it is reused the next time syntax is run, without wrapping
98          it in another layer. */
99       proto = psppire_data_store_get_proto (pdw->data_store);
100       case_cnt = psppire_data_store_get_case_count (pdw->data_store);
101       reader = lazy_casereader_create (proto, case_cnt,
102                                        create_casereader_from_data_store,
103                                        pdw->data_store, &pdw->lazy_serial);
104       dataset_set_source (pdw->dataset, reader);
105
106       if (pdw == window)
107         session_set_active_dataset (the_session, pdw->dataset);
108
109       g_return_val_if_fail (dataset_has_source (pdw->dataset), FALSE);
110
111       pdw->dataset_seqno = dataset_seqno (pdw->dataset);
112     }
113
114   lexer = lex_create ();
115   psppire_set_lexer (lexer);
116   lex_append (lexer, lex_reader);
117
118   for (;;)
119     {
120       struct dataset *ds = session_active_dataset (the_session);
121       enum cmd_result result = cmd_parse (lexer, ds);
122
123       if ( cmd_result_is_failure (result))
124         {
125           retval = FALSE;
126           if ( lex_get_error_mode (lexer) == LEX_ERROR_STOP )
127             break;
128         }
129
130       if ( result == CMD_EOF || result == CMD_FINISH)
131         break;
132     }
133
134   ll_for_each_safe (pdw, next_pdw, PsppireDataWindow, ll, &all_data_windows)
135     {
136       struct dataset *ds;
137
138       ds = session_get_dataset_by_seqno (the_session, pdw->dataset_seqno);
139       if (ds != NULL)
140         {
141           struct casereader *reader;
142
143           pdw->dataset = ds;
144           proc_execute (pdw->dataset);
145
146           psppire_dict_replace_dictionary (pdw->data_store->dict,
147                                            dataset_dict (pdw->dataset));
148
149           reader = dataset_steal_source (pdw->dataset);
150           if (!lazy_casereader_destroy (reader, pdw->lazy_serial))
151             psppire_data_store_set_reader (pdw->data_store, reader);
152
153           g_object_set (G_OBJECT (pdw), "id", dataset_name (pdw->dataset),
154                         (void *) NULL);
155         }
156       else
157         gtk_widget_destroy (GTK_WIDGET (pdw));
158     }
159
160   session_for_each_dataset (the_session, new_pdw_cb, NULL);
161
162   /* Destroy the lexer only after obtaining the dataset, because the dataset
163      might depend on the lexer, if the casereader specifies inline data.  (In
164      such a case then we'll always get an error message--the inline data is
165      missing, otherwise it would have been parsed in the loop above.) */
166   lex_destroy (lexer);
167   psppire_set_lexer (NULL);
168
169   output_flush ();
170
171   return retval;
172 }
173
174 /* Executes null-terminated string SYNTAX as syntax.
175    Returns SYNTAX. */
176 gchar *
177 execute_syntax_string (PsppireDataWindow *window, gchar *syntax)
178 {
179   execute_const_syntax_string (window, syntax);
180   return syntax;
181 }
182
183 /* Executes null-terminated string SYNTAX as syntax. */
184 void
185 execute_const_syntax_string (PsppireDataWindow *window, const gchar *syntax)
186 {
187   execute_syntax (window, lex_reader_for_string (syntax));
188 }