Windows Makefile/NSI installer updates (Internet downloading!) plus bugfixes
[jben.git] / src / dialog_config.cpp
blobc723db39879ad115726351c3400195fc957ac2e4
1 /*
2 Project: J-Ben
3 Website: http://www.vultaire.net/software/jben/
4 License: GNU General Public License (GPL) version 2
5 (http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt)
7 File: dialog_config.cpp
8 Author: Paul Goins
9 Contributors: Alain Bertrand
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>
25 #include "dialog_config.h"
26 #include "preferences.h"
27 #include "kdict.h"
28 #include "file_utils.h"
29 #include "jben_defines.h"
30 #include <glibmm/i18n.h>
31 #include <gtkmm/notebook.h>
32 #include <gtkmm/scrolledwindow.h>
33 #include <gtkmm/buttonbox.h>
34 #include <gtkmm/stock.h>
35 #include <gtkmm/fontselection.h>
36 #include <gtkmm/messagedialog.h>
37 #include <boost/format.hpp>
39 #define CHOOSE_FONT _("Change...")
41 DialogConfig::DialogConfig(Gtk::Window& parent)
42 : StoredDialog(_("Preferences Editor"), parent, "gui.dlg.preferences.size"),
43 chkReadings(_("Include on-yomi, kun-yomi and nanori (name) readings")),
44 chkMeanings(_("Include English meanings")),
45 chkHighImp(_("Include stroke count, Jouyou grade "
46 "and newspaper frequency rank")),
47 chkMultiRad(_("Include radical component list")),
48 chkDict(_("Include dictionary reference codes")),
49 chkVocabCrossRef(_("Show vocab from your study list "
50 "which use the kanji")),
51 chkLowImp(_("Other information (Radical #'s, "
52 "Korean and Pinyin romanization)")),
53 chkSodStatic(_("Use stroke order diagrams if present")),
54 chkSodAnim(_("Use animated stroke order diagrams if present (tests only)")),
55 tblFonts(4, 3),
56 lblJaNormal(_("Japanese Font, Normal")),
57 lblJaLarge (_("Japanese Font, Large")),
58 lblEnNormal(_("English Font, Normal")),
59 lblEnSmall (_("English Font, Small")),
60 btnJaNormal(CHOOSE_FONT),
61 btnJaLarge (CHOOSE_FONT),
62 btnEnNormal(CHOOSE_FONT),
63 btnEnSmall (CHOOSE_FONT),
64 chkMobile(_("Mobile mode (settings saved to current directory)")),
65 btnCancel(Gtk::Stock::CANCEL),
66 btnOK(Gtk::Stock::OK)
68 std::vector<Gtk::CheckButton*>::iterator it;
70 /* Create list of dictionary checkbuttons */
71 Gtk::CheckButton* pc;
72 pc = manage(
73 new Gtk::CheckButton(_("\"New Japanese-English Character Dictionary\" "
74 "by Jack Halpern.")));
75 vChkDict.push_back(pc);
76 pc = manage(
77 new Gtk::CheckButton(_("\"Modern Reader's Japanese-English "
78 "Character Dictionary\" by Andrew Nelson")));
79 vChkDict.push_back(pc);
80 pc = manage(
81 new Gtk::CheckButton(_("\"The New Nelson Japanese-English "
82 "Character Dictionary\" by John Haig")));
83 vChkDict.push_back(pc);
84 pc = manage(
85 new Gtk::CheckButton(_("\"Japanese for Busy People\" by AJLT")));
86 vChkDict.push_back(pc);
87 pc = manage(
88 new Gtk::CheckButton(_("\"The Kanji Way to Japanese Language Power\" "
89 "by Dale Crowley")));
90 vChkDict.push_back(pc);
91 pc = manage(new Gtk::CheckButton(_("\"Kodansha Compact Kanji Guide\"")));
92 vChkDict.push_back(pc);
93 pc = manage(
94 new Gtk::CheckButton(_("\"A Guide To Reading and Writing Japanese\" "
95 "by Ken Hensall et al.")));
96 vChkDict.push_back(pc);
97 pc = manage(
98 new Gtk::CheckButton(_("\"Kanji in Context\" by Nishiguchi and Kono")));
99 vChkDict.push_back(pc);
100 pc = manage(
101 new Gtk::CheckButton(_("\"Kanji Learner's Dictionary\" "
102 "by Jack Halpern")));
103 vChkDict.push_back(pc);
104 pc = manage(
105 new Gtk::CheckButton(_("\"Essential Kanji\" by P.G. O'Neill")));
106 vChkDict.push_back(pc);
107 pc = manage(
108 new Gtk::CheckButton(_("\"2001 Kanji\" by Father Joseph De Roo")));
109 vChkDict.push_back(pc);
110 pc = manage(
111 new Gtk::CheckButton(_("\"A Guide To Reading and Writing Japanese\" "
112 "by Florence Sakade")));
113 vChkDict.push_back(pc);
114 pc = manage(
115 new Gtk::CheckButton(_("\"Tuttle Kanji Cards\" by Alexander Kask")));
116 vChkDict.push_back(pc);
117 pc = manage(
118 new Gtk::CheckButton(_("\"Japanese Kanji Flashcards\" "
119 "by White Rabbit Press")));
120 vChkDict.push_back(pc);
121 pc = manage(
122 new Gtk::CheckButton(_("SKIP codes used by Halpern dictionaries")));
123 vChkDict.push_back(pc);
124 pc = manage(
125 new Gtk::CheckButton(_("\"Kanji Dictionary\" by Spahn & Hadamitzky")));
126 vChkDict.push_back(pc);
127 pc = manage(
128 new Gtk::CheckButton(_("\"Kanji & Kana\" by Spahn & Hadamitzky")));
129 vChkDict.push_back(pc);
130 pc = manage(
131 new Gtk::CheckButton(_("Four Corner code (various dictionaries)")));
132 vChkDict.push_back(pc);
133 pc = manage(new Gtk::CheckButton(_("\"Morohashi Daikanwajiten\"")));
134 vChkDict.push_back(pc);
135 pc = manage(
136 new Gtk::CheckButton(_("\"A Guide to Remembering Japanese Characters\" "
137 "by Kenneth G. Henshal")));
138 vChkDict.push_back(pc);
139 pc = manage(
140 new Gtk::CheckButton(_("Gakken Kanji Dictionary "
141 "(\"A New Dictionary of Kanji Usage\")")));
142 vChkDict.push_back(pc);
143 pc = manage(
144 new Gtk::CheckButton(_("\"Remembering The Kanji\" by James Heisig")));
145 vChkDict.push_back(pc);
146 pc = manage(new Gtk::CheckButton(_("\"Japanese Names\" by P.G. O'Neill")));
148 /* Connect signals */
149 chkDict.signal_toggled()
150 .connect(sigc::mem_fun(*this, &DialogConfig::OnDictionaryToggle));
151 btnCancel.signal_clicked()
152 .connect(sigc::mem_fun(*this, &DialogConfig::OnCancel));
153 btnOK.signal_clicked()
154 .connect(sigc::mem_fun(*this, &DialogConfig::OnOK));
156 /* Layout and display */
157 Gtk::Notebook *pnb = manage(new Gtk::Notebook);
158 Gtk::VBox *pvbKanjiConfig, *pvbFontConfig;
159 Gtk::VBox *pvbKanjiMainOpts, *pvbKanjiDictsOuter, *pvbKanjiOtherOpts;
160 pvbKanjiConfig = manage(new Gtk::VBox);
161 pvbKanjiMainOpts = manage(new Gtk::VBox);
162 pvbKanjiDictsOuter = manage(new Gtk::VBox);
163 pvbKanjiOtherOpts = manage(new Gtk::VBox);
164 pvbFontConfig = manage(new Gtk::VBox);
165 Gtk::HButtonBox *phbbButtons = manage(new Gtk::HButtonBox);
166 Gtk::ScrolledWindow *pswDicts = manage(new Gtk::ScrolledWindow);
167 pswDicts->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
169 pvbKanjiConfig->pack_start(*pvbKanjiMainOpts, Gtk::PACK_SHRINK);
170 pvbKanjiConfig->pack_start(*pvbKanjiDictsOuter, Gtk::PACK_EXPAND_WIDGET);
171 pvbKanjiConfig->pack_start(*pvbKanjiOtherOpts, Gtk::PACK_SHRINK);
172 pvbKanjiConfig->pack_start(*phbbButtons, Gtk::PACK_SHRINK);
174 pvbKanjiMainOpts->pack_start(chkReadings, Gtk::PACK_SHRINK);
175 pvbKanjiMainOpts->pack_start(chkMeanings, Gtk::PACK_SHRINK);
176 pvbKanjiMainOpts->pack_start(chkHighImp, Gtk::PACK_SHRINK);
177 pvbKanjiMainOpts->pack_start(chkMultiRad, Gtk::PACK_SHRINK);
179 pvbKanjiDictsOuter->pack_start(chkDict, Gtk::PACK_SHRINK);
180 pvbKanjiDictsOuter->pack_start(*pswDicts, Gtk::PACK_EXPAND_WIDGET);
182 pswDicts->add(vbDicts);
183 for(it = vChkDict.begin(); it != vChkDict.end(); it++) {
184 vbDicts.pack_start(**it, Gtk::PACK_SHRINK);
186 vbDicts.set_sensitive(false);
188 pvbKanjiOtherOpts->pack_start(chkVocabCrossRef, Gtk::PACK_SHRINK);
189 pvbKanjiOtherOpts->pack_start(chkLowImp, Gtk::PACK_SHRINK);
190 pvbKanjiOtherOpts->pack_start(chkSodStatic, Gtk::PACK_SHRINK);
191 pvbKanjiOtherOpts->pack_start(chkSodAnim, Gtk::PACK_SHRINK);
193 pvbFontConfig->set_spacing(5);
194 pvbFontConfig->pack_start(tblFonts, Gtk::PACK_SHRINK);
196 frJaNormal.add(tvJaNormal);
197 frJaNormal.set_shadow_type(Gtk::SHADOW_IN);
198 frJaLarge .add(tvJaLarge);
199 frJaLarge .set_shadow_type(Gtk::SHADOW_IN);
200 frEnNormal.add(tvEnNormal);
201 frEnNormal.set_shadow_type(Gtk::SHADOW_IN);
202 frEnSmall .add(tvEnSmall);
203 frEnSmall .set_shadow_type(Gtk::SHADOW_IN);
204 tvJaNormal.set_accepts_tab(false);
205 tvJaLarge .set_accepts_tab(false);
206 tvEnNormal.set_accepts_tab(false);
207 tvEnSmall .set_accepts_tab(false);
208 tvJaNormal.set_editable(false);
209 tvJaLarge .set_editable(false);
210 tvEnNormal.set_editable(false);
211 tvEnSmall .set_editable(false);
213 Gtk::HButtonBox *fntBtnBox1 = manage(new Gtk::HButtonBox);
214 fntBtnBox1->pack_start(btnJaNormal, Gtk::PACK_SHRINK);
215 Gtk::HButtonBox *fntBtnBox2 = manage(new Gtk::HButtonBox);
216 fntBtnBox2->pack_start(btnJaLarge, Gtk::PACK_SHRINK);
217 Gtk::HButtonBox *fntBtnBox3 = manage(new Gtk::HButtonBox);
218 fntBtnBox3->pack_start(btnEnNormal, Gtk::PACK_SHRINK);
219 Gtk::HButtonBox *fntBtnBox4 = manage(new Gtk::HButtonBox);
220 fntBtnBox4->pack_start(btnEnSmall, Gtk::PACK_SHRINK);
222 tblFonts.attach(lblJaNormal, 0, 1, 0, 1, Gtk::SHRINK,
223 Gtk::SHRINK, 5, 5);
224 tblFonts.attach(frJaNormal, 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND,
225 Gtk::SHRINK, 5, 5);
226 tblFonts.attach(*fntBtnBox1, 2, 3, 0, 1, Gtk::SHRINK,
227 Gtk::SHRINK, 5, 5);
228 tblFonts.attach(lblJaLarge, 0, 1, 1, 2, Gtk::SHRINK,
229 Gtk::SHRINK, 5, 5);
230 tblFonts.attach(frJaLarge, 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND,
231 Gtk::SHRINK, 5, 5);
232 tblFonts.attach(*fntBtnBox2, 2, 3, 1, 2, Gtk::SHRINK,
233 Gtk::SHRINK, 5, 5);
234 tblFonts.attach(lblEnNormal, 0, 1, 2, 3, Gtk::SHRINK,
235 Gtk::SHRINK, 5, 5);
236 tblFonts.attach(frEnNormal, 1, 2, 2, 3, Gtk::FILL | Gtk::EXPAND,
237 Gtk::SHRINK, 5, 5);
238 tblFonts.attach(*fntBtnBox3, 2, 3, 2, 3, Gtk::SHRINK,
239 Gtk::SHRINK, 5, 5);
240 tblFonts.attach(lblEnSmall, 0, 1, 3, 4, Gtk::SHRINK,
241 Gtk::SHRINK, 5, 5);
242 tblFonts.attach(frEnSmall, 1, 2, 3, 4, Gtk::FILL | Gtk::EXPAND,
243 Gtk::SHRINK, 5, 5);
244 tblFonts.attach(*fntBtnBox4, 2, 3, 3, 4, Gtk::SHRINK,
245 Gtk::SHRINK, 5, 5);
247 btnJaNormal.signal_clicked().connect(sigc::bind<Gtk::Button*>(
248 sigc::mem_fun(*this, &DialogConfig::OnFontChange), &btnJaNormal));
249 btnJaLarge.signal_clicked() .connect(sigc::bind<Gtk::Button*>(
250 sigc::mem_fun(*this, &DialogConfig::OnFontChange), &btnJaLarge));
251 btnEnNormal.signal_clicked().connect(sigc::bind<Gtk::Button*>(
252 sigc::mem_fun(*this, &DialogConfig::OnFontChange), &btnEnNormal));
253 btnEnSmall.signal_clicked() .connect(sigc::bind<Gtk::Button*>(
254 sigc::mem_fun(*this, &DialogConfig::OnFontChange), &btnEnSmall));
256 pnb->append_page(*pvbKanjiConfig, _("Kanji Dictionary"));
257 pnb->append_page(ckt,_("Kanji test"));
258 pnb->append_page(*pvbFontConfig, _("Fonts"));
260 /* Windows only: "mobile mode" */
261 #ifdef __WIN32__
262 chkMobile.signal_toggled()
263 .connect(sigc::mem_fun(*this, &DialogConfig::OnMobileToggle));
264 Gtk::VBox *pvbOtherConfig = manage(new Gtk::VBox);
265 pvbOtherConfig->pack_start(chkMobile, Gtk::PACK_SHRINK);
266 pnb->append_page(*pvbOtherConfig, _("Other"));
267 #endif
269 set_border_width(5);
270 Gtk::VBox* pvb = get_vbox();
271 pvb->set_spacing(5);
272 pvb->pack_start(*pnb);
274 Gtk::HButtonBox* phbb = get_action_area();
275 phbb->pack_start(btnCancel);
276 phbb->pack_start(btnOK);
278 Update();
279 show_all_children();
282 void DialogConfig::OnDictionaryToggle() {
283 vbDicts.set_sensitive(chkDict.get_active());
286 void DialogConfig::OnCancel() {
287 Update();
288 response(Gtk::RESPONSE_CANCEL);
291 void DialogConfig::OnOK() {
292 unsigned long options=0, dictionaries=0;
293 if(chkReadings .get_active()) options |= KDO_READINGS;
294 if(chkMeanings .get_active()) options |= KDO_MEANINGS;
295 if(chkHighImp .get_active()) options |= KDO_HIGHIMPORTANCE;
296 if(chkMultiRad .get_active()) options |= KDO_MULTIRAD;
297 if(chkDict .get_active()) options |= KDO_DICTIONARIES;
298 if(chkVocabCrossRef.get_active()) options |= KDO_VOCABCROSSREF;
299 if(chkLowImp .get_active()) options |= KDO_LOWIMPORTANCE;
300 if(chkSodStatic .get_active()) options |= KDO_SOD_STATIC;
301 if(chkSodAnim .get_active()) options |= KDO_SOD_ANIM;
303 for(size_t i=0; i<vChkDict.size(); i++) {
304 if(vChkDict[i]->get_active()) dictionaries |= (1ul << i);
306 Preferences *prefs = Preferences::Get();
307 prefs->kanjidicOptions = options;
308 prefs->kanjidicDictionaries = dictionaries;
309 ckt.validate(); /* Validate kanji test settings */
310 prefs->GetSetting("font.ja") = sFontJaNormal;
311 prefs->GetSetting("font.ja.large") = sFontJaLarge;
312 prefs->GetSetting("font.en") = sFontEnNormal;
313 prefs->GetSetting("font.en.small") = sFontEnSmall;
315 if(chkMobile.get_active())
316 prefs->GetSetting("config_save_target") = "mobile";
317 else
318 prefs->GetSetting("config_save_target") = "home";
320 Update(); /* Probably unnecessary, but let's be safe. */
321 response(Gtk::RESPONSE_OK);
324 void DialogConfig::Update() {
325 Preferences *prefs = Preferences::Get();
326 int options = prefs->kanjidicOptions;
327 int dictionaries = prefs->kanjidicDictionaries;
329 /* Set appropriate checkboxes */
330 chkReadings .set_active(options & KDO_READINGS);
331 chkMeanings .set_active(options & KDO_MEANINGS);
332 chkHighImp .set_active(options & KDO_HIGHIMPORTANCE);
333 chkMultiRad .set_active(options & KDO_MULTIRAD);
334 chkDict .set_active(options & KDO_DICTIONARIES);
335 chkVocabCrossRef.set_active(options & KDO_VOCABCROSSREF);
336 chkLowImp .set_active(options & KDO_LOWIMPORTANCE);
337 chkSodStatic .set_active(options & KDO_SOD_STATIC);
338 chkSodAnim .set_active(options & KDO_SOD_ANIM);
340 #if 0
341 /* Enable/disable SOD/SODA checkboxes based on existance of directory */
342 /* (DISABLED for now; J-Ben should auto-disable the flag if dicts
343 are not found, but obviously that needs to be done in the prefs
344 loader. I'll add that later.) */
345 string sodDir = Preferences::Get()->GetSetting("sod_dir");
346 chkSodStatic.set_sensitive(
347 FileExists(
348 string(sodDir)
349 .append(1,DSCHAR)
350 .append("sod-utf8-hex")
351 .append(1,DSCHAR)
352 .append("README-License").c_str()));
353 chkSodAnim.set_sensitive(
354 FileExists(
355 string(sodDir)
356 .append(1,DSCHAR)
357 .append("soda-utf8-hex")
358 .append(1,DSCHAR)
359 .append("README-License").c_str()));
360 #endif
362 for(size_t i=0;i<vChkDict.size();i++) {
363 vChkDict[i]->set_active(dictionaries & (1ul << i));
366 /* Init font display */
367 sFontJaNormal = prefs->GetSetting("font.ja");
368 sFontJaLarge = prefs->GetSetting("font.ja.large");
369 sFontEnNormal = prefs->GetSetting("font.en");
370 sFontEnSmall = prefs->GetSetting("font.en.small");
371 UpdateFontControl(tvJaNormal, sFontJaNormal);
372 UpdateFontControl(tvJaLarge, sFontJaLarge);
373 UpdateFontControl(tvEnNormal, sFontEnNormal);
374 UpdateFontControl(tvEnSmall, sFontEnSmall);
376 /* Other Options */
377 chkMobile.set_active(prefs->GetSetting("config_save_target") == "mobile");
380 void DialogConfig::UpdateFontControl(Gtk::TextView& tv, const string& font) {
381 Glib::RefPtr<Gtk::TextBuffer> pBuf = tv.get_buffer();
382 Glib::RefPtr<Gtk::TextTagTable> pTable = pBuf->get_tag_table();
383 Glib::RefPtr<Gtk::TextTag> pTag;
384 pTag = pTable->lookup("font");
385 if(pTag!=0) {
386 pTable->remove(pTag);
387 pTag.clear();
389 pTag = Gtk::TextTag::create("font");
390 pTag->property_font() = font;
391 pTable->add(pTag);
392 pBuf->set_text("");
393 if(&tv == &tvJaNormal || &tv == &tvJaLarge) {
394 pBuf->insert_with_tag(pBuf->begin(), "日本語", pTag);
395 } else {
396 pBuf->insert_with_tag(pBuf->begin(), "English", pTag);
400 void DialogConfig::OnFontChange(Gtk::Button* src) {
401 Gtk::FontSelectionDialog fd(_("Choose Font"));
402 Gtk::TextView* ptv;
403 string* ps;
404 if(src==&btnJaNormal) {
405 ptv = &tvJaNormal;
406 ps = &sFontJaNormal;
407 fd.set_preview_text("ENGLISH english 日本語 にほんご ニホンゴ");
408 } else if(src==&btnJaLarge) {
409 ptv = &tvJaLarge;
410 ps = &sFontJaLarge;
411 fd.set_preview_text("ENGLISH english 日本語 にほんご ニホンゴ");
412 } else if(src==&btnEnNormal) {
413 ptv = &tvEnNormal;
414 ps = &sFontEnNormal;
415 } else if(src==&btnEnSmall) {
416 ptv = &tvEnSmall;
417 ps = &sFontEnSmall;
418 } else return; /* Should not happen */
420 fd.set_font_name(*ps);
421 int result = fd.run();
422 if(result == Gtk::RESPONSE_OK) {
423 (*ps) = fd.get_font_name();
424 UpdateFontControl(*ptv, *ps);
428 void DialogConfig::OnMobileToggle() {
429 if(chkMobile.get_active()==false) {
430 Preferences *p = Preferences::Get();
431 if(p->GetSetting("config_save_target")=="mobile") {
432 /* The user is attempting a change from a mobile to standard
433 install. We need to check whether a standard install config
434 file is already present, and if it is, we need to warn the
435 user before they accidentally overwrite it. */
436 string sCfgPath;
437 char *sz = getenv(HOMEENV);
438 if(sz) {
439 sCfgPath = sz;
440 sCfgPath.append(1, DSCHAR);
441 sCfgPath.append(CFGFILE);
442 } else return; /* No home dir is a problem of its own, but at least
443 the user won't lose data over the problem. */
444 if(FileExists(sCfgPath.c_str())) {
445 Gtk::MessageDialog md(
446 (boost::format(_(
447 "A config file was found in this system's home folder: "
448 "%s. Turning mobile mode off will cause J-Ben to "
449 "OVERWRITE the existing file when it closes, "
450 "destroying whatever is already there. Is this okay?"))
451 % sCfgPath).str(),
452 false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO);
453 int result = md.run();
454 if(result == Gtk::RESPONSE_NO) {
455 chkMobile.set_active(true);