Major directory structure changes, plus a bug fix.
[jben.git] / src / preferences.cpp
blob391d8e719ef454eec98ac9e78adf03127f69b835
1 /*
2 Project: J-Ben
3 Author: Paul Goins
4 Website: http://www.vultaire.net/software/jben/
5 License: GNU General Public License (GPL) version 2
6 (http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt)
8 File: preferences.cpp
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>
24 #ifndef JB_DATADIR
25 # define JB_DATADIR "."
26 #endif
28 #ifdef __WXMSW__
29 # define CFGFILE "jben.cfg"
30 # define HOMEENV "APPDATA"
31 #else
32 # define CFGFILE ".jben"
33 # define HOMEENV "HOME"
34 #endif
36 #define CURRENT_CONFIG_VERSION "1.1"
38 #include "preferences.h"
39 #include "kdict.h"
40 #include "listmanager.h"
41 #include "file_utils.h"
42 #include "encoding_convert.h"
43 #include "string_utils.h"
44 #include "errorlog.h"
45 #include <sstream>
46 #include <fstream>
47 #include <iostream>
48 #include <iomanip>
49 #include <cstdlib>
50 using namespace std;
52 Preferences* Preferences::prefsSingleton = NULL;
54 Preferences *Preferences::Get() {
55 if(!prefsSingleton) {
56 prefsSingleton = new Preferences;
57 /* Load with default preferences, and overwrite with any stored
58 preferences. */
59 prefsSingleton->SetDefaultPrefs();
61 /* Check for the config file in the user's home directory. */
62 string homedir = getenv(HOMEENV);
63 homedir.append(1, DSCHAR);
64 bool OK = (prefsSingleton
65 ->LoadFile(string(homedir).append(CFGFILE).c_str())
66 == REF_SUCCESS);
68 /* If the config file could not be loaded from the home directory,
69 fall back and check the current directory. */
70 if(!OK)
71 prefsSingleton->LoadFile(CFGFILE);
73 return prefsSingleton;
76 Preferences::Preferences() {
77 /* Nothing to be done */
80 void Preferences::Destroy() {
81 if(prefsSingleton) {
82 delete prefsSingleton;
83 prefsSingleton = NULL;
87 void Preferences::SetDefaultPrefs() {
88 kanjidicOptions =
89 KDO_READINGS | KDO_MEANINGS | KDO_HIGHIMPORTANCE | KDO_VOCABCROSSREF;
90 kanjidicDictionaries = 0;
91 stringOpts["config_version"] = CURRENT_CONFIG_VERSION;
92 stringOpts["config_save_target"] = "home";
93 stringOpts["kdict_kanjidic2"]
94 = JB_DATADIR DSSTR "dicts" DSSTR "kanjidic2.xml";
95 stringOpts["kdict_kanjidic"] = JB_DATADIR DSSTR "dicts" DSSTR "kanjidic";
96 stringOpts["kdict_kanjd212"] = JB_DATADIR DSSTR "dicts" DSSTR "kanjd212";
97 stringOpts["kdict_kradfile"] = JB_DATADIR DSSTR "dicts" DSSTR "kradfile";
98 stringOpts["kdict_radkfile"] = JB_DATADIR DSSTR "dicts" DSSTR "radkfile";
99 stringOpts["wdict_edict2"] = JB_DATADIR DSSTR "dicts" DSSTR "edict2";
100 stringOpts["sod_dir"] = JB_DATADIR DSSTR "sods";
103 int Preferences::LoadFile(const char *filename) {
104 wstring s;
105 kanjidicOptions = KDO_ALL | KDO_UNHANDLED;
106 kanjidicDictionaries = 0; /* KDD_ALL */
108 int e = ReadEncodedFile(filename, s);
109 if(e==REF_SUCCESS) {
110 ostringstream oss;
111 oss << "Preferences file \"" << filename
112 << "\" loaded successfully.";
113 el.Push(EL_Silent, oss.str());
115 /* Split into strings for each line */
116 list<wstring> tokenList = StrTokenize<wchar_t>(s, L"\n");
117 wstring token, subToken;
118 size_t index;
119 while(tokenList.size()>0) {
120 token = tokenList.front();
121 tokenList.pop_front();
122 if( (token.length()>0) && (token[0]!=L'#') ) {
123 /* We only want to split the string into two subtokens, so we'll
124 do it manually. */
125 index = token.find_first_of(L" \t");
126 if(index!=wstring::npos) {
127 subToken = token.substr(0, index);
128 subToken = ToLower(subToken);
130 if(subToken==L"kanjidicoptionmask") {
131 subToken = token.substr(index+1);
132 subToken = Trim(subToken);
133 /* We know the subtoken starts with 0x, so skip the
134 first two characters. */
135 wistringstream(subToken.substr(2))
136 >> hex >> kanjidicOptions;
138 } else if(subToken==L"kanjidicdictionarymask") {
139 subToken = token.substr(index+1);
140 subToken = Trim(subToken);
141 wistringstream(subToken.substr(2))
142 >> hex >> kanjidicDictionaries;
144 } else if(subToken==L"vocablist") {
145 subToken = token.substr(index+1);
146 subToken = Trim(subToken);
147 list<wstring> tSub
148 = StrTokenize<wchar_t>(subToken, L";");
149 while(tSub.size()>0) {
150 subToken = tSub.front();
151 tSub.pop_front();
152 if(subToken.length()>0) {
153 string *temp = &stringOpts["vocablist"];
154 if(temp->length()>0)
155 temp->append(1, '\n');
156 temp->append(utfconv_wm(subToken));
160 } else {
161 /* Default handling for any
162 other string-based entries */
163 string key = utfconv_wm(subToken);
164 subToken = token.substr(index+1);
165 stringOpts[key] = utfconv_wm(Trim(subToken));
167 } else {
168 /* No space/tab was found. Check no-arg options, if any.
169 (Currently there are none.) */
171 } /* if(tokenlen>0, token[0]!=# */
172 } /* while(hasmoretokens) */
173 } /* if(file opened) */
174 else {
175 ostringstream oss;
176 oss << "Preferences file \"" << filename
177 << "\" could NOT be loaded." << endl;
178 el.Push(EL_Silent, oss.str());
181 /* The file is now loaded.
182 Upgrade it to the latest version, if necessary. */
183 if(stringOpts["config_version"] != CURRENT_CONFIG_VERSION)
184 UpgradeConfigFile();
186 return e;
189 void Preferences::UpgradeConfigFile() {
190 string version = stringOpts["config_version"];
191 /* Iterate through the version-wise changes */
192 if(version=="1") {
193 el.Push(EL_Silent, "Upgrading config file from version 1 to 1.1.");
194 /* 1 to 1.1:
195 - Add config_save_target setting
196 - Add KANJIDIC2 and KANJD212 default settings */
197 stringOpts["config_save_target"] = "home";
198 stringOpts["kdict_kanjidic2"]
199 = JB_DATADIR DSSTR "dicts" DSSTR "kanjidic2.xml";
200 stringOpts["kdict_kanjd212"]
201 = JB_DATADIR DSSTR "dicts" DSSTR "kanjd212";
202 version = "1.1";
204 stringOpts["config_version"] = CURRENT_CONFIG_VERSION;
207 Preferences::~Preferences() {
208 string prefs = GetPrefsStr();
209 ofstream ofile;
210 string filename;
211 if(ToLower(stringOpts["config_save_target"]) == "home") {
212 filename = string(getenv(HOMEENV)).append(1, DSCHAR).append(CFGFILE);
213 ofile.open(filename.c_str(), ios::out | ios::binary);
215 if(!ofile.is_open()) {
216 filename = CFGFILE;
217 ofile.open(filename.c_str(), ios::out | ios::binary);
220 ostringstream oss;
221 if(ofile.is_open()) {
222 ofile << prefs;
223 oss << "Preferences file \"" << filename
224 << "\" saved successfully.";
225 el.Push(EL_Silent, oss.str());
227 else {
228 oss << "Unable to save preferences to file \"" << CFGFILE
229 << "\"!";
230 el.Push(EL_Error, oss.str());
233 ofile.close();
236 string Preferences::GetPrefsStr() {
237 ostringstream prefs;
238 string kanjiList, vocabList;
240 /* Output config version first */
241 prefs << "config_version\t" << stringOpts["config_version"] << '\n';
243 /* Get kanji and vocab lists in UTF-8 encoded strings */
244 /* Currently we only save one list, "master", the currently selected one. */
245 ListManager* lm = ListManager::Get();
246 kanjiList = utfconv_wm(lm->KList()->ToString());
247 vocabList = utfconv_wm(lm->VList()->ToString(';'));
249 prefs << "KanjidicOptionMask\t0x"
250 << uppercase << hex << setw(8) << setfill('0')
251 << kanjidicOptions << '\n';
252 prefs << "KanjidicDictionaryMask\t0x"
253 << uppercase << hex << setw(8) << setfill('0')
254 << kanjidicDictionaries << '\n';
255 prefs << "KanjiList\t" << kanjiList << '\n';
256 prefs << "VocabList\t" << vocabList << '\n';
258 /* Append any other variables stored */
259 for(map<string, string>::iterator mi = stringOpts.begin();
260 mi != stringOpts.end(); mi++) {
261 if(mi->first!="kanjilist" &&
262 mi->first!="vocablist" &&
263 mi->first!="config_version") {
264 prefs << mi->first << '\t' << mi->second << '\n';
268 return prefs.str();
271 string& Preferences::GetSetting(string key) {
272 return stringOpts[ToLower(key)];