OSDN Git Service

a1a2aa3e4792544b956d99cb860dad9f0d9f18b1
[eb123/eb123.git] / src / prefs.c
1
2 #include "defs.h"
3
4 #include "builder.h"
5 #include "dicts.h"
6 #include "history.h"
7 #include "mainwnd.h"
8 #include "popupwnd.h"
9 #include "prefs.h"
10 #include "hotkeys.h"
11 #include "textview.h"
12
13 G_DEFINE_TYPE(Prefs, prefs, G_TYPE_OBJECT);
14
15 typedef struct
16 {
17     int type;
18     char *name;
19     union
20     {
21         int i;
22         char *s;
23     } val;
24 } pref1;
25
26 static Prefs *_prefs = NULL;
27
28 static const pref1 prefs_list[] =
29 {
30     {G_TYPE_INT, "headword.maxhits", {50}},
31     {G_TYPE_INT, "dictbar.word_hist", {30}},
32     {G_TYPE_INT, "selection.maxchar", {32}},
33     {G_TYPE_INT, "selection.lookup_started", {0}},
34     {G_TYPE_INT, "hotkeys.ignore_locks", {1}},
35     {G_TYPE_INT, "popupwnd.w", {350}},
36     {G_TYPE_INT, "popupwnd.h", {450}},
37     {G_TYPE_INT, "popupwnd.x", {300}},
38     {G_TYPE_INT, "popupwnd.y", {300}},
39     {G_TYPE_INT, "popupwnd.remember_pos", {0}},
40     {G_TYPE_INT, "popupwnd.lock", {0}},
41     {G_TYPE_INT, "popupwnd.jap_only", {0}},
42     {G_TYPE_INT, "popupwnd.timeout", {2000}},
43     {G_TYPE_INT, "popupwnd.maxhits", {5}},
44     {G_TYPE_INT, "popupwnd.search_method", {0}},
45     {G_TYPE_INT, "mainwnd.x", {300}},
46     {G_TYPE_INT, "mainwnd.y", {300}},
47     {G_TYPE_INT, "mainwnd.w", {500}},
48     {G_TYPE_INT, "mainwnd.h", {400}},
49     {G_TYPE_INT, "mainwnd.remember_pos", {1}},
50     {G_TYPE_INT, "mainwnd.search", {0}},
51     {G_TYPE_INT, "mainwnd.custom_font", {0}},
52     {G_TYPE_INT, "paned.tree_width", {150}},
53     {G_TYPE_INT, "highlight_all_keywords", {1}},
54     {G_TYPE_INT, "prepend_title", {1}},
55     {G_TYPE_INT, "prepend_len", {1}},
56     {G_TYPE_INT, "headword.use_tree", {0}},
57     {G_TYPE_STRING, "mainwnd.font", {.s = ""}},
58     {G_TYPE_STRING, "color.link", {.s = "#0000c0"}},
59     {G_TYPE_STRING, "color.keyword", {.s = "#c00000"}},
60     {G_TYPE_STRING, "color.title", {.s = "#306090"}}
61 };
62
63 static void prefs_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec)
64 {
65     Prefs *prefs = PREFS(object);
66
67     switch(param_id)
68     {
69         case 1:
70             prefs->builder = BUILDER(g_value_get_pointer(value));
71             break;
72         default:
73             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
74             break;
75     }
76 }
77
78
79 static void prefs_class_init(PrefsClass *klass)
80 {
81     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
82     gobject_class->set_property = prefs_set_property;
83     g_object_class_install_property(gobject_class, 1, g_param_spec_pointer("builder", _("Builder"), _("Builder"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
84 }
85
86 static void prefs_init(Prefs *self)
87 {
88     if(!_prefs)
89         _prefs = self;
90     else
91         g_assert(1);
92
93     //GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass);
94     //gst_element_class_add_pad_template(gstelement_class, gst_static_pad_template_get(&prefs_template));
95
96     g_datalist_init(&(self->data));
97
98     gchar *home_dir = getenv("HOME");
99     gchar *userdir = g_strdup_printf("%s%s.%s", home_dir, G_DIR_SEPARATOR_S, PACKAGE_NAME);
100     prefs_set_str(self, "userdir", userdir);
101
102     GDir *dir;
103     if((dir = g_dir_open(userdir, 0, NULL)) == NULL)
104     {
105         if(g_mkdir_with_parents(userdir, 493))
106         {
107             LOG(LOG_CRITICAL, "Failed to create directory: %s\n", userdir);
108             exit(1);
109         }
110     }
111     else
112         g_dir_close(dir);
113 }
114
115 enum
116 {
117     PREF_TITLE,
118     PREF_NUMBER,
119     PREF_N
120 };
121
122 static void prefs_selection_changed_cb(GtkTreeSelection *selection, gpointer data)
123 {
124     GtkTreeIter iter;
125     GtkTreeModel *model;
126     if(!gtk_tree_selection_get_selected(selection, &model, &iter)) return;
127
128     GtkNotebook *notebook = GTK_NOTEBOOK(data);
129     gint n;
130     gtk_tree_model_get(model, &iter, 1, &n, -1);
131     if(n >= 0)
132         gtk_notebook_set_current_page(notebook, n);
133 }
134
135 static const pref1* prefs_get1(Prefs *p, const gchar *str)
136 {
137     gint i;
138     for(i = 0; i < SZ(prefs_list); i++)
139     {
140         const pref1 *p1 = &(prefs_list[i]);
141         if(!g_strcmp0(p1->name, str))
142             return p1;
143     }
144     return 0;
145 }
146
147 static void prefs_set_widget_data(Prefs *p, Builder *b, const gchar *str)
148 {
149     const pref1 *p1 = prefs_get1(p, str);
150     if(p1->type == G_TYPE_INT)
151     {
152         gint value = prefs_get_int(p, str);
153         builder_set_int(b, str, value);
154     }
155     if(p1->type == G_TYPE_STRING)
156     {
157         const gchar *value = prefs_get_str(p, str);
158         builder_set_str(b, str, value);
159     }
160 }
161
162 static void prefs_get_widget_data(Prefs *p, Builder *b, const gchar *str)
163 {
164     const pref1 *p1 = prefs_get1(p, str);
165     if(p1->type == G_TYPE_INT)
166     {
167         gint value = builder_get_int(b, str);
168         prefs_set_int(p, str, value);
169     }
170     if(p1->type == G_TYPE_STRING)
171     {
172         const gchar *value = builder_get_str(b, str);
173         prefs_set_str(p, str, value);
174     }
175 }
176
177 gboolean preferences_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
178 {
179     gtk_widget_hide(widget);
180     return TRUE;
181 }
182
183 void prefs_ok_btn_clicked_cb(GtkWidget *widget, gpointer data)
184 {
185     Mainwnd *mw = MAINWND(data);
186     GtkWidget *wnd = gtk_widget_get_toplevel(widget);
187     gtk_widget_hide(wnd);
188     gint i;
189     for(i = 0; i < SZ(prefs_list); i++)
190     {
191         const pref1 *p1 = &(prefs_list[i]);
192         prefs_get_widget_data(mw->prefs, mw->builder, p1->name);
193     }
194     prefs_save(mw->prefs);
195     mainwnd_reset_font(mw);
196     mainwnd_reset_headwords(mw);
197     GtkBox *vbox = GTK_BOX(gtk_builder_get_object(GTK_BUILDER(mw->builder), "hotkeys_vbox"));
198     hotkeys_reload(mw->hotkeys, vbox);
199     hotkeys_local_install(mw->hotkeys);
200     hotkeys_global_install(mw->hotkeys);
201     hotkeys_save(mw->hotkeys);
202 }
203
204 void prefs_close_wnd(Prefs *prefs)
205 {
206     GtkWidget *w = GTK_WIDGET(gtk_builder_get_object(GTK_BUILDER(prefs->builder), "preferences"));
207     gtk_widget_hide(w);
208 }
209
210 void prefs_cancel_btn_clicked_cb(GtkWidget *widget, gpointer data)
211 {
212     Mainwnd *mw = MAINWND(data);
213     prefs_close_wnd(mw->prefs);
214 }
215
216 void prefs_btn_clicked_cb(GtkWidget *widget, gpointer data)
217 {
218     Mainwnd *mw = MAINWND(data);
219     Prefs *prefs = mw->prefs;
220
221     GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object(GTK_BUILDER(mw->builder), "preferences"));
222     gtk_widget_hide_on_delete(wnd);
223
224     GtkTreeView *prefs_tree = GTK_TREE_VIEW(gtk_builder_get_object(GTK_BUILDER(mw->builder), "prefs_tree"));
225     GtkTreeStore *prefs_store = GTK_TREE_STORE(gtk_builder_get_object(GTK_BUILDER(mw->builder), "prefs_store"));
226     GtkTreeSelection *select = gtk_tree_view_get_selection(prefs_tree);
227     GtkTreeIter iter1, iter2;
228     static gboolean preparewnd = True;
229     if(preparewnd)
230     {
231         GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
232         gtk_tree_view_insert_column_with_attributes(prefs_tree, -1, _("Items"), renderer, "text", 0, NULL);
233
234         GtkNotebook *notebook = GTK_NOTEBOOK(gtk_builder_get_object(GTK_BUILDER(mw->builder), "notebook1"));
235         gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
236         g_signal_connect(G_OBJECT(select), "changed", G_CALLBACK(prefs_selection_changed_cb), notebook);
237
238         gint n = gtk_notebook_get_n_pages(notebook);
239         gint i;
240         for(i = 0; i < n; i++)
241         {
242             GtkWidget *p = gtk_notebook_get_nth_page(notebook, i);
243             GtkWidget *l = gtk_notebook_get_tab_label(notebook, p);
244             const gchar *text = gtk_label_get_text(GTK_LABEL(l));
245             if(text[0] != '_')
246             {
247                 gtk_tree_store_append(prefs_store, &iter1, NULL);
248                 gtk_tree_store_set(prefs_store, &iter1, 0, _(text), 1, i, -1);
249             }
250             else
251             {
252                 gtk_tree_store_append(prefs_store, &iter2, &iter1);
253                 gtk_tree_store_set(prefs_store, &iter2, 0, _(&(text[1])), 1, i, -1);
254             }
255         }
256         builder_install_text_cellrenderer(mw->builder, "popupwnd.search_method");
257         for(i = 0; i < SZ(prefs_list); i++)
258         {
259             const pref1 *p1 = &(prefs_list[i]);
260             prefs_set_widget_data(prefs, mw->builder, p1->name);
261         }
262         GtkWidget *w = GTK_WIDGET(gtk_builder_get_object(GTK_BUILDER(mw->builder), "mainwnd.font"));
263         gtk_widget_set_sensitive(w, prefs_get_int(mw->prefs, "mainwnd.custom_font"));
264
265         Hotkeys *hotkeys = mw->hotkeys;
266         GtkBox *vbox = GTK_BOX(gtk_builder_get_object(GTK_BUILDER(mw->builder), "hotkeys_vbox"));
267         for(i = 0; (w = hotkeys_edit_nth(hotkeys, i)); i++)
268         {
269             gtk_box_pack_start(vbox, w, FALSE, FALSE, 0);
270         }
271         preparewnd = False;
272     }
273     if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(prefs_store), &iter1))
274     {
275         gtk_tree_selection_select_iter(select, &iter1);
276     }
277     gtk_tree_view_expand_all(prefs_tree);
278     gtk_widget_show_all(wnd);
279 }
280
281 void prefs_save(Prefs *self)
282 {
283     printf("prefs_save\n");
284     gint i, j;
285     gchar filename[PATH_MAX], buff[128];
286     const gchar *str;
287     xmlDocPtr doc = xmlNewDoc((xmlChar*)"1.0");
288     doc->children = xmlNewDocRawNode(doc, NULL, (xmlChar*)"Prefs", NULL);
289
290     const gchar *userdir = prefs_get_str(self, "userdir");
291     sprintf(filename, "%s%s%s", userdir, G_DIR_SEPARATOR_S, FILENAME_PREFS);
292     
293     for(i = 0 ; i < SZ(prefs_list); i++)
294     {
295         const pref1 *p = &(prefs_list[i]);
296         switch(prefs_list[i].type)
297         {
298         case G_TYPE_INT:
299         case G_TYPE_BOOLEAN:
300             j = prefs_get_int(self, p->name);
301             sprintf(buff, "%d", j);
302             break;
303         case G_TYPE_FLOAT:
304             break;
305         case G_TYPE_STRING:
306             str = prefs_get_str(self, p->name);
307             if(str)
308                 sprintf(buff, "%s", str);
309             break;
310         }
311         xmlNodePtr node = xmlAddChild(doc->children, xmlNewNode(NULL, (xmlChar*)prefs_list[i].name));
312         xmlNewProp(node, (xmlChar*)"value", (xmlChar*)buff);
313     }
314     xmlSaveFormatFileEnc(filename, doc, "utf8", 0);
315     xmlFreeDoc(doc);
316 }
317
318 void prefs_load_elem(void *ctx, const xmlChar *name, const xmlChar **atts)
319 {
320     gint i;
321     xmlParserCtxt *ctxt = (xmlParserCtxt*)ctx;
322     xmlSAXHandler *cb = ctxt->sax;
323     Prefs *prefs = PREFS(cb->_private);
324     for(i = 0; i < SZ(prefs_list); i++)
325     {
326         if(!g_strcmp0((gchar*)name, prefs_list[i].name))
327         {
328             switch(prefs_list[i].type){
329             case G_TYPE_INT:
330             case G_TYPE_BOOLEAN:
331                 prefs_set_int(prefs, (const gchar*)name, atoi((gchar*)atts[1]));
332                 break;
333             case G_TYPE_STRING:
334                 prefs_set_str(prefs, (const gchar*)name, strdup((gchar*)atts[1]));
335                 break;
336             case G_TYPE_FLOAT:
337                 break;
338             }
339         }
340     }
341 }
342
343 void prefs_load(Prefs *self)
344 {
345     gchar filename[PATH_MAX];
346     xmlSAXHandler cb;
347     const gchar *userdir = prefs_get_str(self, "userdir");
348     sprintf(filename, "%s%s%s", userdir, G_DIR_SEPARATOR_S, FILENAME_PREFS);
349     if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
350         return;
351     memset(&cb, 0, sizeof(xmlSAXHandler));
352     cb.startElement = &prefs_load_elem;
353     cb._private = self;
354     xmlDocPtr doc = xmlSAXParseFile(&cb, filename, 0);
355     xmlFreeDoc(doc);
356 }
357
358 gint prefs_get_int(Prefs *self, const gchar *name)
359 {
360     gpointer ptr = g_datalist_get_data(&self->data, name);
361     return (gint)ptr;
362 }
363
364 void prefs_set_int(Prefs *self, const gchar *name, gint value)
365 {
366     g_datalist_set_data(&self->data, name, (gpointer)value);
367 }
368
369 const gchar* prefs_get_str(Prefs *self, const gchar *name)
370 {
371     gpointer ptr = g_datalist_get_data(&self->data, name);
372     return (const gchar*)ptr;
373 }
374
375 void prefs_set_str(Prefs *self, const gchar *name, const gchar *value)
376 {
377     g_datalist_set_data(&self->data, name, (gpointer)value);
378 }
379
380 const gchar* prefs_get_userdir()
381 {
382     return prefs_get_str(_prefs, "userdir");
383 }
384
385 void prefs_custom_font_toggled_cb(GtkToggleButton *btn, gpointer data)
386 {
387     Mainwnd *mw = MAINWND(data);
388     GtkWidget *w = GTK_WIDGET(gtk_builder_get_object(GTK_BUILDER(mw->builder), "mainwnd.font"));
389     gtk_widget_set_sensitive(w, gtk_toggle_button_get_active(btn));
390 }
391