d75bff359b1d33aac4b0d8f177a259e47d014903
[pspp] / src / ui / gui / psppire.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2004, 2005, 2006, 2009, 2010  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/psppire.h"
20
21 #include <assert.h>
22 #include <gsl/gsl_errno.h>
23 #include <gtk/gtk.h>
24 #include <libintl.h>
25 #include <unistd.h>
26
27 #include "data/casereader.h"
28 #include "data/datasheet.h"
29 #include "data/file-handle-def.h"
30 #include "data/file-name.h"
31 #include "data/por-file-reader.h"
32 #include "data/procedure.h"
33 #include "data/settings.h"
34 #include "data/sys-file-reader.h"
35 #include "language/lexer/lexer.h"
36 #include "language/syntax-string-source.h"
37 #include "libpspp/getl.h"
38 #include "libpspp/i18n.h"
39 #include "libpspp/message.h"
40 #include "libpspp/version.h"
41 #include "output/driver.h"
42 #include "output/journal.h"
43 #include "output/message-item.h"
44 #include "ui/gui/dict-display.h"
45 #include "ui/gui/executor.h"
46 #include "ui/gui/psppire-data-store.h"
47 #include "ui/gui/psppire-data-window.h"
48 #include "ui/gui/psppire-dict.h"
49 #include "ui/gui/psppire-output-window.h"
50 #include "ui/gui/psppire-selector.h"
51 #include "ui/gui/psppire-var-store.h"
52 #include "ui/gui/psppire-var-view.h"
53 #include "ui/gui/psppire-window-register.h"
54 #include "ui/gui/psppire.h"
55 #include "ui/gui/widgets.h"
56 #include "ui/source-init-opts.h"
57 #include "ui/syntax-gen.h"
58
59 #include "gl/configmake.h"
60 #include "gl/xalloc.h"
61 #include "gl/relocatable.h"
62
63 GtkRecentManager *the_recent_mgr = 0;
64 PsppireDataStore *the_data_store = 0;
65 PsppireVarStore *the_var_store = 0;
66
67 static void create_icon_factory (void);
68
69 struct source_stream *the_source_stream ;
70 struct dataset * the_dataset = NULL;
71
72 static GtkWidget *the_data_window;
73
74 static void handle_msg (const struct msg *);
75 static void load_data_file (const char *);
76
77 static void
78 replace_casereader (struct casereader *s)
79 {
80   psppire_data_store_set_reader (the_data_store, s);
81 }
82
83 #define _(msgid) gettext (msgid)
84 #define N_(msgid) msgid
85
86
87
88
89 void
90 initialize (struct source_stream *ss, const char *data_file)
91 {
92   PsppireDict *dictionary = 0;
93
94   i18n_init ();
95
96   preregister_widgets ();
97
98   gsl_set_error_handler_off ();
99   settings_init (&viewer_width, &viewer_length);
100   fh_init ();
101
102   the_dataset = create_dataset ();
103
104   the_source_stream = ss;
105   msg_init (ss, handle_msg);
106
107   dictionary = psppire_dict_new_from_dict (dataset_dict (the_dataset));
108
109   bind_textdomain_codeset (PACKAGE, "UTF-8");
110
111   /* Create the model for the var_sheet */
112   the_var_store = psppire_var_store_new (dictionary);
113
114   the_data_store = psppire_data_store_new (dictionary);
115   replace_casereader (NULL);
116
117   create_icon_factory ();
118
119   psppire_output_window_setup ();
120
121   journal_enable ();
122   textdomain (PACKAGE);
123
124
125   the_recent_mgr = gtk_recent_manager_get_default ();
126
127   psppire_selector_set_default_selection_func (GTK_TYPE_ENTRY, insert_source_row_into_entry);
128   psppire_selector_set_default_selection_func (PSPPIRE_VAR_VIEW_TYPE, insert_source_row_into_tree_view);
129   psppire_selector_set_default_selection_func (GTK_TYPE_TREE_VIEW, insert_source_row_into_tree_view);
130
131   the_data_window = psppire_data_window_new ();
132   if (data_file != NULL)
133     load_data_file (data_file);
134
135   execute_syntax (create_syntax_string_source (""));
136
137   gtk_widget_show (the_data_window);
138 }
139
140
141 void
142 de_initialize (void)
143 {
144   destroy_source_stream (the_source_stream);
145   settings_done ();
146   output_close ();
147   i18n_done ();
148 }
149
150
151 static void
152 func (gpointer key, gpointer value, gpointer data)
153 {
154   gboolean rv;
155   PsppireWindow *window = PSPPIRE_WINDOW (value);
156
157   g_signal_emit_by_name (window, "delete-event", 0, &rv);
158 }
159
160 void
161 psppire_quit (void)
162 {
163   PsppireWindowRegister *reg = psppire_window_register_new ();
164   psppire_window_register_foreach (reg, func, NULL);
165
166   gtk_main_quit ();
167 }
168
169
170 struct icon_info
171 {
172   const char *file_name;
173   const gchar *id;
174 };
175
176
177 static const struct icon_info icons[] =
178   {
179     {PKGDATADIR "/value-labels.png",    "pspp-value-labels"},
180     {PKGDATADIR "/weight-cases.png",    "pspp-weight-cases"},
181     {PKGDATADIR "/goto-variable.png",   "pspp-goto-variable"},
182     {PKGDATADIR "/insert-variable.png", "pspp-insert-variable"},
183     {PKGDATADIR "/insert-case.png",     "pspp-insert-case"},
184     {PKGDATADIR "/split-file.png",      "pspp-split-file"},
185     {PKGDATADIR "/select-cases.png",    "pspp-select-cases"},
186     {PKGDATADIR "/recent-dialogs.png",  "pspp-recent-dialogs"},
187     {PKGDATADIR "/nominal.png",         "var-nominal"},
188     {PKGDATADIR "/ordinal.png",         "var-ordinal"},
189     {PKGDATADIR "/scale.png",           "var-scale"},
190     {PKGDATADIR "/string.png",          "var-string"},
191     {PKGDATADIR "/date-scale.png",      "var-date-scale"}
192   };
193
194 static void
195 create_icon_factory (void)
196 {
197   gint i;
198   GtkIconFactory *factory = gtk_icon_factory_new ();
199
200   for (i = 0 ; i < sizeof (icons) / sizeof(icons[0]); ++i)
201     {
202       GError *err = NULL;
203       GdkPixbuf *pixbuf =
204         gdk_pixbuf_new_from_file (relocate (icons[i].file_name), &err);
205
206       if ( pixbuf )
207         {
208           GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
209           g_object_unref (pixbuf);
210           gtk_icon_factory_add ( factory, icons[i].id, icon_set);
211         }
212       else
213         {
214           g_warning ("Cannot create icon: %s", err->message);
215           g_clear_error (&err);
216         }
217     }
218
219   {
220     /* Create our own "pspp-stock-reset" item, using the
221        GTK_STOCK_REFRESH icon set */
222
223     GtkStockItem items[] = {
224       {"pspp-stock-reset", N_("_Reset"), 0, 0, PACKAGE},
225       {"pspp-stock-select", N_("_Select"), 0, 0, PACKAGE}
226     };
227
228
229     gtk_stock_add (items, 2);
230     gtk_icon_factory_add (factory, "pspp-stock-reset",
231                           gtk_icon_factory_lookup_default (GTK_STOCK_REFRESH)
232                           );
233
234     gtk_icon_factory_add (factory, "pspp-stock-select",
235                           gtk_icon_factory_lookup_default (GTK_STOCK_INDEX)
236                           );
237   }
238
239   gtk_icon_factory_add_default (factory);
240 }
241 \f
242 static void
243 load_data_file (const char *arg)
244 {
245   gchar *filename = NULL;
246   gchar *utf8 = NULL;
247   const gchar *local_encoding = NULL;
248   gsize written = -1;
249   const gboolean local_is_utf8 = g_get_charset (&local_encoding);
250
251   /* There seems to be no Glib function to convert from local encoding
252      to filename encoding.  Therefore it has to be done in two steps:
253      the intermediate encoding is UTF8.
254
255      Either step could fail.  However, in many cases the file can still
256      be loaded even if the conversion fails. So in those cases, after showing
257      a warning, we simply copy the locally encoded filename to the destination
258      and hope for the best.
259   */
260
261   if ( local_is_utf8)
262     {
263       utf8 = xstrdup (arg);
264     }
265   else
266     {
267       GError *err = NULL;
268       utf8 = g_locale_to_utf8 (arg, -1, NULL, &written, &err);
269       if ( NULL == utf8)
270         {
271           g_warning ("Cannot convert filename from local encoding \"%s\" to UTF-8: %s",
272                      local_encoding,
273                      err->message);
274           g_clear_error (&err);
275         }
276     }
277
278   if ( NULL != utf8)
279     {
280       GError *err = NULL;
281       filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
282       if ( NULL == filename)
283         {
284           g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
285                      err->message);
286           g_clear_error (&err);
287         }
288     }
289
290   g_free (utf8);
291
292   if ( filename == NULL)
293     filename = xstrdup (arg);
294
295   psppire_window_load (PSPPIRE_WINDOW (the_data_window), filename);
296
297   g_free (filename);
298 }
299
300 static void
301 handle_msg (const struct msg *m)
302 {
303   message_item_submit (message_item_create (m));
304 }