New (singleton) object psppire-window-register
[pspp-builds.git] / src / ui / gui / psppire-window.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008  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 <gtk/gtksignal.h>
20 #include <gtk/gtkwindow.h>
21 #include <gtk/gtkcheckmenuitem.h>
22
23 #include <stdlib.h>
24
25 #include <gettext.h>
26 #define _(msgid) gettext (msgid)
27 #define N_(msgid) msgid
28
29 #include "psppire-window.h"
30 #include "psppire-window-register.h"
31
32 static void psppire_window_base_finalize (PsppireWindowClass *, gpointer);
33 static void psppire_window_base_init     (PsppireWindowClass *class);
34 static void psppire_window_class_init    (PsppireWindowClass *class);
35 static void psppire_window_init          (PsppireWindow      *window);
36
37
38 static PsppireWindowClass *the_class;
39 static GObjectClass *parent_class;
40
41 GType
42 psppire_window_get_type (void)
43 {
44   static GType psppire_window_type = 0;
45
46   if (!psppire_window_type)
47     {
48       static const GTypeInfo psppire_window_info =
49       {
50         sizeof (PsppireWindowClass),
51         (GBaseInitFunc) psppire_window_base_init,
52         (GBaseFinalizeFunc) psppire_window_base_finalize,
53         (GClassInitFunc) psppire_window_class_init,
54         (GClassFinalizeFunc) NULL,
55         NULL,
56         sizeof (PsppireWindow),
57         0,
58         (GInstanceInitFunc) psppire_window_init,
59       };
60
61       psppire_window_type =
62         g_type_register_static (GTK_TYPE_WINDOW, "PsppireWindow",
63                                 &psppire_window_info, 0);
64     }
65
66   return psppire_window_type;
67 }
68
69
70 /* Properties */
71 enum
72 {
73   PROP_0,
74   PROP_FILENAME,
75   PROP_USAGE
76 };
77
78
79 gchar *
80 uniquify (const gchar *str, int *x)
81 {
82   return g_strdup_printf ("%s%d", str, (*x)++);
83 }
84
85
86
87 static void
88 psppire_window_set_property (GObject         *object,
89                              guint            prop_id,
90                              const GValue    *value,
91                              GParamSpec      *pspec)
92 {
93   PsppireWindow *window = PSPPIRE_WINDOW (object);
94
95   switch (prop_id)
96     {
97     case PROP_USAGE:
98       window->usage = g_value_get_enum (value);
99       break;
100     case PROP_FILENAME:
101       {
102         gchar mdash[6] = {0,0,0,0,0,0};
103         gchar *basename, *title;
104         const gchar *name = g_value_get_string (value);
105         gchar *candidate_name = strdup (name);
106         int x = 0;
107
108         PsppireWindowRegister *reg = psppire_window_register_new ();
109
110         while ( psppire_window_register_lookup (reg, candidate_name))
111           {
112             free (candidate_name);
113             candidate_name = uniquify (name, &x);
114           }
115
116         basename = g_path_get_basename (candidate_name);
117         g_unichar_to_utf8 (0x2014, mdash);
118
119         switch (window->usage)
120           {
121           case PSPPIRE_WINDOW_USAGE_SYNTAX:
122             title = g_strdup_printf ( _("%s %s PSPPIRE Syntax Editor"),
123                                       basename, mdash);
124             break;
125           case PSPPIRE_WINDOW_USAGE_OUTPUT:
126             title = g_strdup_printf ( _("%s %s PSPPIRE Output"),
127                                       basename, mdash);
128           case PSPPIRE_WINDOW_USAGE_DATA:
129             title = g_strdup_printf ( _("%s %s PSPPIRE Data Editor"),
130                                       basename, mdash);
131             break;
132           default:
133             g_assert_not_reached ();
134             break;
135           }
136
137         gtk_window_set_title (GTK_WINDOW (window), title);
138
139         if ( window->name)
140           psppire_window_register_remove (reg, window->name);
141
142         free (window->name);
143         window->name = candidate_name;
144
145         psppire_window_register_insert (reg, window, window->name);
146
147         free (basename);
148         free (title);
149       }
150       break;
151     default:
152       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
153       break;
154     };
155 }
156
157
158 static void
159 psppire_window_get_property (GObject         *object,
160                              guint            prop_id,
161                              GValue          *value,
162                              GParamSpec      *pspec)
163 {
164   PsppireWindow *window = PSPPIRE_WINDOW (object);
165
166   switch (prop_id)
167     {
168     case PROP_USAGE:
169       g_value_set_enum (value, window->usage);
170       break;
171     case PROP_FILENAME:
172       g_value_set_string (value, window->name);
173       break;
174     default:
175       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176       break;
177     };
178 }
179
180
181
182 static void
183 psppire_window_finalize (GObject *object)
184 {
185   PsppireWindow *window = PSPPIRE_WINDOW (object);
186   
187   PsppireWindowRegister *reg = psppire_window_register_new ();
188
189   psppire_window_register_remove (reg, window->name);
190   free (window->name);
191
192   g_signal_handler_disconnect (psppire_window_register_new (),
193                                window->remove_handler);
194
195   g_signal_handler_disconnect (psppire_window_register_new (),
196                                window->insert_handler);
197
198   g_hash_table_destroy (window->menuitem_table);
199
200   if (G_OBJECT_CLASS (parent_class)->finalize)
201     G_OBJECT_CLASS (parent_class)->finalize (object);
202 }
203
204
205 static void
206 psppire_window_class_init (PsppireWindowClass *class)
207 {
208   GObjectClass *object_class = G_OBJECT_CLASS (class);
209
210   GParamSpec *use_class_spec =
211     g_param_spec_enum ("usage",
212                        "Usage",
213                        "What the window is used for",
214                        G_TYPE_PSPPIRE_WINDOW_USAGE,
215                        PSPPIRE_WINDOW_USAGE_SYNTAX /* default value */,
216                        G_PARAM_CONSTRUCT_ONLY |G_PARAM_READABLE | G_PARAM_WRITABLE);
217
218
219   GParamSpec *filename_spec =
220     g_param_spec_string ("filename",
221                        "File name",
222                        "The name of the file associated with this window, if any",
223                          "Untitled",
224                          G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT
225                          );
226
227
228   object_class->set_property = psppire_window_set_property;
229   object_class->get_property = psppire_window_get_property;
230
231   g_object_class_install_property (object_class,
232                                    PROP_FILENAME,
233                                    filename_spec);
234
235   g_object_class_install_property (object_class,
236                                    PROP_USAGE,
237                                    use_class_spec);
238
239
240   the_class = class;
241   parent_class = g_type_class_peek_parent (class);
242 }
243
244
245 static void
246 psppire_window_base_init (PsppireWindowClass *class)
247 {
248   GObjectClass *object_class = G_OBJECT_CLASS (class);
249
250   object_class->finalize = psppire_window_finalize;
251 }
252
253
254
255 static void
256 psppire_window_base_finalize (PsppireWindowClass *class,
257                                 gpointer class_data)
258 {
259 }
260
261 static void
262 insert_menuitem_into_menu (PsppireWindow *window, gpointer key)
263 {
264   GtkWidget *item = gtk_check_menu_item_new_with_label (key);
265
266   gtk_widget_show (item);
267   
268   gtk_menu_shell_append (window->menu, item);
269
270   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
271                                   (psppire_window_register_lookup (psppire_window_register_new (), key) == window));
272
273   g_hash_table_insert (window->menuitem_table, key, item);
274 }
275
276 static void
277 insert_item (gpointer key, gpointer value, gpointer data)
278 {
279   PsppireWindow *window = PSPPIRE_WINDOW (data);
280
281   if ( NULL != g_hash_table_lookup (window->menuitem_table, key))
282     return;
283
284   insert_menuitem_into_menu (window, key);
285 }
286
287 /* Insert a new item into the window menu */
288 static void
289 insert_menuitem (GObject *reg, const gchar *key, gpointer data)
290 {
291   PsppireWindow *window = PSPPIRE_WINDOW (data);
292   
293   insert_menuitem_into_menu (window, (gpointer) key);
294 }
295
296
297 static void
298 remove_menuitem (PsppireWindowRegister *reg, const gchar *key, gpointer data)
299 {
300   PsppireWindow *window = PSPPIRE_WINDOW (data);
301   GtkWidget *item ;
302
303   if ( !GTK_WIDGET_REALIZED (window))
304     return;
305
306   item = g_hash_table_lookup (window->menuitem_table, key);
307
308   g_hash_table_remove (window->menuitem_table, key);
309
310   gtk_container_remove (GTK_CONTAINER (window->menu), item);
311 }
312
313 static void
314 insert_existing_items (PsppireWindow *window)
315 {
316   psppire_window_register_foreach (psppire_window_register_new (), insert_item, window);
317 }
318
319 static void
320 psppire_window_init (PsppireWindow *window)
321 {
322   window->name = NULL;
323   window->menu = NULL;
324
325   window->menuitem_table  = g_hash_table_new (g_str_hash, g_str_equal);
326
327
328   g_signal_connect (window,  "realize", G_CALLBACK (insert_existing_items), NULL);
329
330   window->insert_handler = g_signal_connect (psppire_window_register_new (),
331                                              "inserted",
332                                              G_CALLBACK (insert_menuitem),
333                                              window);
334
335   window->remove_handler = g_signal_connect (psppire_window_register_new (),
336                                              "removed",
337                                              G_CALLBACK (remove_menuitem),
338                                              window);
339 }
340
341
342 GtkWidget*
343 psppire_window_new (PsppireWindowUsage usage)
344 {
345   return GTK_WIDGET (g_object_new (psppire_window_get_type (),
346                                    "type", GTK_WINDOW_TOPLEVEL,
347                                    "usage", usage,
348                                    NULL));
349 }
350
351
352 const gchar *
353 psppire_window_get_filename (PsppireWindow *w)
354 {
355   const gchar *name = NULL;
356   g_object_get (w, "filename", name, NULL);
357   return name;
358 }
359
360
361 void
362 psppire_window_set_filename (PsppireWindow *w, const gchar *filename)
363 {
364   g_object_set (w, "filename", filename, NULL);
365 }
366
367 \f
368
369 GType
370 psppire_window_usage_get_type (void)
371 {
372   static GType etype = 0;
373   if (etype == 0)
374     {
375       static const GEnumValue values[] = {
376         { PSPPIRE_WINDOW_USAGE_SYNTAX, "PSPPIRE_WINDOW_USAGE_SYNTAX",
377           "Syntax" },
378
379         { PSPPIRE_WINDOW_USAGE_OUTPUT, "PSPPIRE_WINDOW_USAGE_OUTPUT",
380           "Output" },
381
382         { PSPPIRE_WINDOW_USAGE_DATA,   "PSPPIRE_WINDOW_USAGE_DATA",
383           "Data" },
384
385         { 0, NULL, NULL }
386       };
387
388       etype = g_enum_register_static (g_intern_static_string ("PsppireWindowUsage"),
389                                       values);
390     }
391
392   return etype;
393 }
394
395
396
397 static void
398 minimise_window (gpointer key, gpointer value, gpointer data)
399 {
400   gtk_window_iconify (GTK_WINDOW (value));
401 }
402
403
404 void
405 psppire_window_minimise_all (void)
406 {
407   PsppireWindowRegister *reg = psppire_window_register_new ();
408
409   g_hash_table_foreach (reg->name_table, minimise_window, NULL);
410 }