r201: Allowed dragging to a subdirectory to save into it.
[rox-filer.git] / ROX-Filer / src / options.c
blob688f385019c812ba20e1cd0afb3db26d0bdd3c87
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 1999, 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 <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <glib.h>
28 #include <gtk/gtk.h>
30 #include "gui_support.h"
31 #include "choices.h"
32 #include "options.h"
34 /* Add OptionsSection structs to this list in your _init() functions */
35 GSList *options_sections = NULL;
37 static GtkWidget *window, *sections_vbox;
38 static FILE *save_file = NULL;
39 static GHashTable *option_hash = NULL;
41 enum {BUTTON_SAVE, BUTTON_OK, BUTTON_APPLY};
43 /* Static prototypes */
44 static void save_options(GtkWidget *widget, gpointer data);
45 static char *process_option_line(guchar *line);
47 void options_init()
49 GtkWidget *tl_vbox, *scrolled_area;
50 GtkWidget *border, *label;
51 GtkWidget *actions, *button;
52 char *string, *save_path;
54 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
55 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
56 gtk_window_set_title(GTK_WINDOW(window), "ROX-Filer options");
57 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
58 GTK_SIGNAL_FUNC(hide_dialog_event), window);
59 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
60 gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
62 tl_vbox = gtk_vbox_new(FALSE, 4);
63 gtk_container_add(GTK_CONTAINER(window), tl_vbox);
65 scrolled_area = gtk_scrolled_window_new(NULL, NULL);
66 gtk_container_set_border_width(GTK_CONTAINER(scrolled_area), 4);
67 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
68 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
69 gtk_box_pack_start(GTK_BOX(tl_vbox), scrolled_area, TRUE, TRUE, 0);
71 border = gtk_frame_new(NULL);
72 gtk_frame_set_shadow_type(GTK_FRAME(border), GTK_SHADOW_NONE);
73 gtk_container_set_border_width(GTK_CONTAINER(border), 4);
74 gtk_scrolled_window_add_with_viewport(
75 GTK_SCROLLED_WINDOW(scrolled_area), border);
77 sections_vbox = gtk_vbox_new(FALSE, 4);
78 gtk_container_add(GTK_CONTAINER(border), sections_vbox);
80 save_path = choices_find_path_save("...", FALSE);
81 if (save_path)
83 string = g_strconcat("Choices will be saved as ",
84 save_path,
85 NULL);
86 label = gtk_label_new(string);
87 g_free(string);
89 else
90 label = gtk_label_new("Choices saving is disabled by "
91 "CHOICESPATH variable");
92 gtk_box_pack_start(GTK_BOX(tl_vbox), label, FALSE, TRUE, 0);
94 actions = gtk_hbox_new(TRUE, 16);
95 gtk_box_pack_start(GTK_BOX(tl_vbox), actions, FALSE, TRUE, 0);
97 button = gtk_button_new_with_label("Save");
98 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
99 if (!save_path)
100 gtk_widget_set_sensitive(button, FALSE);
101 gtk_signal_connect(GTK_OBJECT(button), "clicked",
102 GTK_SIGNAL_FUNC(save_options), (gpointer) BUTTON_SAVE);
104 button = gtk_button_new_with_label("OK");
105 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
106 gtk_signal_connect(GTK_OBJECT(button), "clicked",
107 GTK_SIGNAL_FUNC(save_options), (gpointer) BUTTON_OK);
109 button = gtk_button_new_with_label("Apply");
110 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
111 gtk_signal_connect(GTK_OBJECT(button), "clicked",
112 GTK_SIGNAL_FUNC(save_options), (gpointer) BUTTON_APPLY);
114 button = gtk_button_new_with_label("Cancel");
115 gtk_box_pack_start(GTK_BOX(actions), button, FALSE, TRUE, 0);
116 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
117 GTK_SIGNAL_FUNC(gtk_widget_hide), GTK_OBJECT(window));
120 void options_load(void)
122 static gboolean need_init = TRUE;
123 char *path;
125 if (need_init)
127 GtkWidget *group;
128 GSList *next = options_sections;
130 while (next)
132 OptionsSection *section = (OptionsSection *) next->data;
134 group = gtk_frame_new(section->name);
135 gtk_box_pack_start(GTK_BOX(sections_vbox), group,
136 FALSE, TRUE, 0);
137 gtk_container_add(GTK_CONTAINER(group),
138 section->create());
139 next = next->next;
142 need_init = FALSE;
145 path = choices_find_path_load("options");
146 if (!path)
147 return; /* Nothing to load */
149 parse_file(path, process_option_line);
152 void parse_file(char *path, ParseFunc *parse_line)
154 char *data;
155 long length;
157 if (load_file(path, &data, &length))
159 char *eol, *error;
160 char *line = data;
161 int line_number = 1;
163 while (line && *line)
165 eol = strchr(line, '\n');
166 if (eol)
167 *eol = '\0';
169 error = parse_line(line);
171 if (error)
173 GString *message;
175 message = g_string_new(NULL);
176 g_string_sprintf(message,
177 "Error in options file at line %d: "
178 "\n\"%s\"\n"
179 "This may be due to upgrading from "
180 "a previous version of ROX-Filer. "
181 "Open the Options window and click "
182 "on Save.",
183 line_number,
184 error);
185 delayed_error("ROX-Filer", message->str);
186 g_string_free(message, TRUE);
187 break;
190 if (!eol)
191 break;
192 line = eol + 1;
193 line_number++;
195 g_free(data);
199 /* Call this on init to register a handler for a key (thing before the = in
200 * the config file).
201 * The function returns a pointer to an error messages (which will
202 * NOT be free()d), or NULL on success.
204 void option_register(char *key, OptionFunc *func)
206 if (!option_hash)
207 option_hash = g_hash_table_new(g_str_hash, g_str_equal);
208 g_hash_table_insert(option_hash, key, func);
211 /* Process one line from the options file (\0 term'd).
212 * Returns NULL on success, or a pointer to an error message.
213 * The line is modified.
215 static char *process_option_line(guchar *line)
217 guchar *eq, *c;
218 OptionFunc *func;
220 g_return_val_if_fail(option_hash != NULL, "No registered functions!");
222 eq = strchr(line, '=');
223 if (!eq)
224 return "Missing '='";
226 c = eq - 1;
227 while (c > line && (*c == ' ' || *c == '\t'))
228 c--;
229 c[1] = '\0';
230 c = eq + 1;
231 while (*c == ' ' || *c == '\t')
232 c++;
234 func = (OptionFunc *) g_hash_table_lookup(option_hash, line);
235 if (!func)
236 return "Unknown option";
238 return func(c);
241 static void save_options(GtkWidget *widget, gpointer data)
243 int button = (int) data;
244 GSList *next = options_sections;
246 while (next)
248 OptionsSection *section = (OptionsSection *) next->data;
249 section->set();
250 next = next->next;
253 if (button == BUTTON_SAVE)
255 char *path;
257 path = choices_find_path_save("options", TRUE);
258 g_return_if_fail(path != NULL);
260 save_file = fopen(path, "wb");
261 if (!save_file)
263 char *str;
264 str = g_strconcat("Unable to open '", path,
265 "' for writing: ",
266 g_strerror(errno),
267 NULL);
268 report_error("ROX-Filer", str);
269 g_free(str);
270 return;
273 next = options_sections;
274 while (next)
276 OptionsSection *section = (OptionsSection *) next->data;
277 section->save();
278 next = next->next;
281 if (save_file && fclose(save_file) == EOF)
283 report_error("ROX-Filer", g_strerror(errno));
284 return;
288 if (button != BUTTON_APPLY)
289 gtk_widget_hide(window);
292 void options_show(FilerWindow *filer_window)
294 GSList *next = options_sections;
296 if (GTK_WIDGET_MAPPED(window))
297 gtk_widget_hide(window);
299 while (next)
301 OptionsSection *section = (OptionsSection *) next->data;
302 section->update();
303 next = next->next;
306 gtk_widget_show_all(window);
309 void option_write(char *name, char *value)
311 char *string;
312 int len;
314 if (!save_file)
315 return; /* Error already reported hopefully */
317 string = g_strconcat(name, " = ", value, "\n", NULL);
318 len = strlen(string);
319 if (fwrite(string, sizeof(char), len, save_file) < len)
321 delayed_error("Saving options", g_strerror(errno));
322 fclose(save_file);
323 save_file = NULL;
325 g_free(string);