r233: Tidied up choices.c quite a lot. Also, replaced the 'guess' file with a
[rox-filer/ma.git] / ROX-Filer / src / options.c
bloba55f2bb3173c15ba42864bd8971e22102bcf7fd7
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* options.c - code for handling user choices */
24 #include "config.h"
26 #include <stdio.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <glib.h>
30 #include <gtk/gtk.h>
32 #include "gui_support.h"
33 #include "choices.h"
34 #include "options.h"
36 /* Add OptionsSection structs to this list in your _init() functions */
37 GSList *options_sections = NULL;
39 static GtkWidget *window, *sections_vbox;
40 static FILE *save_file = NULL;
41 static GHashTable *option_hash = NULL;
43 enum {BUTTON_SAVE, BUTTON_OK, BUTTON_APPLY};
45 /* Static prototypes */
46 static void save_options(GtkWidget *widget, gpointer data);
47 static char *process_option_line(guchar *line);
49 void options_init()
51 GtkWidget *tl_vbox, *scrolled_area;
52 GtkWidget *border, *label;
53 GtkWidget *actions, *button;
54 char *string, *save_path;
56 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
57 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
58 gtk_window_set_title(GTK_WINDOW(window), "ROX-Filer options");
59 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
60 GTK_SIGNAL_FUNC(hide_dialog_event), window);
61 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
62 gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
64 tl_vbox = gtk_vbox_new(FALSE, 4);
65 gtk_container_add(GTK_CONTAINER(window), tl_vbox);
67 scrolled_area = gtk_scrolled_window_new(NULL, NULL);
68 gtk_container_set_border_width(GTK_CONTAINER(scrolled_area), 4);
69 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
70 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
71 gtk_box_pack_start(GTK_BOX(tl_vbox), scrolled_area, TRUE, TRUE, 0);
73 border = gtk_frame_new(NULL);
74 gtk_frame_set_shadow_type(GTK_FRAME(border), GTK_SHADOW_NONE);
75 gtk_container_set_border_width(GTK_CONTAINER(border), 4);
76 gtk_scrolled_window_add_with_viewport(
77 GTK_SCROLLED_WINDOW(scrolled_area), border);
79 sections_vbox = gtk_vbox_new(FALSE, 4);
80 gtk_container_add(GTK_CONTAINER(border), sections_vbox);
82 save_path = choices_find_path_save("...", "ROX-Filer", FALSE);
83 if (save_path)
85 string = g_strconcat("Choices will be saved as ",
86 save_path,
87 NULL);
88 label = gtk_label_new(string);
89 g_free(string);
91 else
92 label = gtk_label_new("Choices saving is disabled by "
93 "CHOICESPATH variable");
94 gtk_box_pack_start(GTK_BOX(tl_vbox), label, FALSE, TRUE, 0);
96 actions = gtk_hbox_new(TRUE, 16);
97 gtk_box_pack_start(GTK_BOX(tl_vbox), actions, FALSE, TRUE, 0);
99 button = gtk_button_new_with_label("Save");
100 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
101 if (!save_path)
102 gtk_widget_set_sensitive(button, FALSE);
103 gtk_signal_connect(GTK_OBJECT(button), "clicked",
104 GTK_SIGNAL_FUNC(save_options), (gpointer) BUTTON_SAVE);
106 button = gtk_button_new_with_label("OK");
107 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
108 gtk_signal_connect(GTK_OBJECT(button), "clicked",
109 GTK_SIGNAL_FUNC(save_options), (gpointer) BUTTON_OK);
111 button = gtk_button_new_with_label("Apply");
112 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
113 gtk_signal_connect(GTK_OBJECT(button), "clicked",
114 GTK_SIGNAL_FUNC(save_options), (gpointer) BUTTON_APPLY);
116 button = gtk_button_new_with_label("Cancel");
117 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
118 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
119 GTK_SIGNAL_FUNC(gtk_widget_hide), GTK_OBJECT(window));
122 void options_load(void)
124 static gboolean need_init = TRUE;
125 char *path;
127 if (need_init)
129 GtkWidget *group;
130 GSList *next = options_sections;
132 while (next)
134 OptionsSection *section = (OptionsSection *) next->data;
136 group = gtk_frame_new(section->name);
137 gtk_box_pack_start(GTK_BOX(sections_vbox), group,
138 FALSE, TRUE, 0);
139 gtk_container_add(GTK_CONTAINER(group),
140 section->create());
141 next = next->next;
144 need_init = FALSE;
147 path = choices_find_path_load("options", "ROX-Filer");
148 if (!path)
149 return; /* Nothing to load */
151 parse_file(path, process_option_line);
154 void parse_file(char *path, ParseFunc *parse_line)
156 char *data;
157 long length;
158 gboolean seen_error = FALSE;
160 if (load_file(path, &data, &length))
162 char *eol, *error;
163 char *line = data;
164 int line_number = 1;
166 while (line && *line)
168 eol = strchr(line, '\n');
169 if (eol)
170 *eol = '\0';
172 error = parse_line(line);
174 if (error && !seen_error)
176 GString *message;
178 message = g_string_new(NULL);
179 g_string_sprintf(message,
180 "Error in options file at line %d: "
181 "\n\"%s\"\n"
182 "This may be due to upgrading from "
183 "a previous version of ROX-Filer. "
184 "Open the Options window and click "
185 "on Save.\n"
186 "Further errors will be ignored.",
187 line_number,
188 error);
189 delayed_error("ROX-Filer", message->str);
190 g_string_free(message, TRUE);
191 seen_error = TRUE;
194 if (!eol)
195 break;
196 line = eol + 1;
197 line_number++;
199 g_free(data);
203 /* Call this on init to register a handler for a key (thing before the = in
204 * the config file).
205 * The function returns a pointer to an error messages (which will
206 * NOT be free()d), or NULL on success.
208 void option_register(char *key, OptionFunc *func)
210 if (!option_hash)
211 option_hash = g_hash_table_new(g_str_hash, g_str_equal);
212 g_hash_table_insert(option_hash, key, func);
215 /* Process one line from the options file (\0 term'd).
216 * Returns NULL on success, or a pointer to an error message.
217 * The line is modified.
219 static char *process_option_line(guchar *line)
221 guchar *eq, *c;
222 OptionFunc *func;
224 g_return_val_if_fail(option_hash != NULL, "No registered functions!");
226 eq = strchr(line, '=');
227 if (!eq)
228 return "Missing '='";
230 c = eq - 1;
231 while (c > line && (*c == ' ' || *c == '\t'))
232 c--;
233 c[1] = '\0';
234 c = eq + 1;
235 while (*c == ' ' || *c == '\t')
236 c++;
238 func = (OptionFunc *) g_hash_table_lookup(option_hash, line);
239 if (!func)
240 return "Unknown option";
242 return func(c);
245 static void save_options(GtkWidget *widget, gpointer data)
247 int button = (int) data;
248 GSList *next = options_sections;
250 while (next)
252 OptionsSection *section = (OptionsSection *) next->data;
253 section->set();
254 next = next->next;
257 if (button == BUTTON_SAVE)
259 char *path;
261 path = choices_find_path_save("options", "ROX-Filer", TRUE);
262 g_return_if_fail(path != NULL);
264 save_file = fopen(path, "wb");
265 if (!save_file)
267 char *str;
268 str = g_strconcat("Unable to open '", path,
269 "' for writing: ",
270 g_strerror(errno),
271 NULL);
272 report_error("ROX-Filer", str);
273 g_free(str);
274 return;
277 next = options_sections;
278 while (next)
280 OptionsSection *section = (OptionsSection *) next->data;
281 section->save();
282 next = next->next;
285 if (save_file && fclose(save_file) == EOF)
287 report_error("ROX-Filer", g_strerror(errno));
288 return;
292 if (button != BUTTON_APPLY)
293 gtk_widget_hide(window);
296 void options_show(FilerWindow *filer_window)
298 GSList *next = options_sections;
300 if (GTK_WIDGET_MAPPED(window))
301 gtk_widget_hide(window);
303 while (next)
305 OptionsSection *section = (OptionsSection *) next->data;
306 section->update();
307 next = next->next;
310 gtk_widget_show_all(window);
313 void option_write(char *name, char *value)
315 char *string;
316 int len;
318 if (!save_file)
319 return; /* Error already reported hopefully */
321 string = g_strconcat(name, " = ", value, "\n", NULL);
322 len = strlen(string);
323 if (fwrite(string, sizeof(char), len, save_file) < len)
325 delayed_error("Saving options", g_strerror(errno));
326 fclose(save_file);
327 save_file = NULL;
329 g_free(string);