src/config.cpp

changeset 436
4268a5507725
parent 430
8458cf2719d1
child 455
c5d14d112034
equal deleted inserted replaced
435:bc3a51394953 436:4268a5507725
15 * You should have received a copy of the GNU General Public License 15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18 18
19 #include <errno.h> 19 #include <errno.h>
20 #include <time.h>
21 #include <QDir> 20 #include <QDir>
22 #include <QTextStream> 21 #include <QTextStream>
22 #include <QSettings>
23 #include "common.h" 23 #include "common.h"
24 #include "config.h" 24 #include "config.h"
25 #include "misc.h" 25 #include "misc.h"
26 #include "gui.h" 26 #include "gui.h"
27 #include "file.h"
27 28
28 config* g_configPointers[MAX_CONFIG]; 29 config* g_configPointers[MAX_CONFIG];
29 static ushort g_cfgPointerCursor = 0; 30 static ushort g_cfgPointerCursor = 0;
30 31
31 // ============================================================================= 32 // =============================================================================
33 static QSettings* getSettingsObject() {
34 #ifdef PORTABLE
35 # ifdef _WIN32
36 # define EXTENSION ".ini"
37 # else
38 # define EXTENSION ".cfg"
39 # endif // _WIN32
40 return new QSettings (str (APPNAME).toLower() + EXTENSION, QSettings::IniFormat);
41 #else
42 return new QSettings;
43 #endif // PORTABLE
44 }
45
46 // =============================================================================
32 // Load the configuration from file 47 // Load the configuration from file
33 bool config::load() { 48 bool config::load() {
34 print ("config::load: Loading configuration file...\n"); 49 QSettings* settings = getSettingsObject();
35 print ("config::load: Path to configuration is %1\n", filepath()); 50 print ("config::load: Loading configuration file from %1...\n", settings->fileName());
36
37 // Locale must be disabled for atof
38 setlocale (LC_NUMERIC, "C");
39
40 File f (filepath(), File::Read);
41 int ln = 0;
42
43 if (!f)
44 return false;
45
46 // Read the values.
47 for (str line : f) {
48 ln++;
49
50 if (line.isEmpty() || line[0] == '#')
51 continue; // Empty line or comment.
52
53 // Find the equals sign.
54 int equals = line.indexOf ('=');
55
56 if (equals == -1) {
57 fprint (stderr, "couldn't find `=` sign in entry `%1`\n", line);
58 continue;
59 }
60
61 str entry = line.left (equals);
62 str valstring = line.right (line.length() - equals - 1);
63
64 // Find the config entry for this.
65 config* cfg = null;
66
67 for (config* i : g_configPointers) {
68 if (!i)
69 break;
70
71 if (entry == i->name)
72 cfg = i;
73 }
74
75 if (!cfg) {
76 fprint (stderr, "unknown config `%1`\n", entry);
77 continue;
78 }
79
80 switch (cfg->getType()) {
81 case Type_int:
82 static_cast<intconfig*> (cfg)->value = valstring.toInt();
83 break;
84
85 case Type_str:
86 static_cast<strconfig*> (cfg)->value = valstring;
87 break;
88
89 case Type_float:
90 static_cast<floatconfig*> (cfg)->value = valstring.toFloat();
91 break;
92
93 case Type_bool: {
94 bool& val = static_cast<boolconfig*> (cfg)->value;
95
96 if (valstring.toUpper() == "TRUE" || valstring == "1")
97 val = true;
98 elif (valstring.toUpper() == "FALSE" || valstring == "0")
99 val = false;
100
101 break;
102 }
103
104 case Type_keyseq:
105 static_cast<keyseqconfig*> (cfg)->value = keyseq::fromString (valstring);
106 break;
107
108 default:
109 break;
110 }
111 }
112
113 f.close();
114 return true;
115 }
116
117 extern_cfg (str, io_ldpath);
118
119 // =============================================================================
120 // Save the configuration to disk
121 bool config::save() {
122 // The function will write floats, disable the locale now so that they
123 // are written properly.
124 setlocale (LC_NUMERIC, "C");
125
126 // If the directory doesn't exist, create it now.
127 if (QDir (dirpath()).exists() == false) {
128 fprint (stderr, "Creating config path %1...\n", dirpath());
129
130 if (!QDir().mkpath (dirpath())) {
131 critical ("Failed to create the configuration directory. Configuration cannot be saved!\n");
132 return false;
133 }
134 }
135
136 File f (filepath(), File::Write);
137 print ("writing cfg to %1\n", filepath());
138
139 if (!f) {
140 critical (fmt (QObject::tr ("Cannot save configuration, cannot open %1 for writing: %2\n"),
141 filepath(), strerror (errno)));
142 return false;
143 }
144
145 fprint (f, "# Configuration file for " APPNAME "\n");
146 str valstring;
147 51
148 for (config* cfg : g_configPointers) { 52 for (config* cfg : g_configPointers) {
149 if (!cfg) 53 if (!cfg)
150 break; 54 break;
151 55
152 if (cfg->isDefault()) 56 cfg->loadFromConfig (settings);
153 continue; 57 }
154 58
155 switch (cfg->getType()) { 59 settings->deleteLater();
156 case Type_int: 60 return true;
157 valstring = fmt ("%1", static_cast<intconfig*> (cfg)->value); 61 }
62
63 // =============================================================================
64 void intconfig::loadFromConfig (const QSettings* cfg) {
65 QVariant val = cfg->value (name, str::number (defval));
66 value = val.toInt();
67 }
68
69 void floatconfig::loadFromConfig (const QSettings* cfg) {
70 QVariant val = cfg->value (name, str::number (defval));
71 value = val.toFloat();
72 }
73
74 void strconfig::loadFromConfig (const QSettings* cfg) {
75 QVariant val = cfg->value (name, defval);
76 value = val.toString();
77 }
78
79 void boolconfig::loadFromConfig (const QSettings* cfg) {
80 QVariant val = cfg->value (name, str::number (defval));
81 value = val.toBool();
82 }
83
84 void keyseqconfig::loadFromConfig (const QSettings* cfg) {
85 QVariant val = cfg->value (name, defval.toString());
86 value = keyseq (val.toString());
87 }
88
89 // =============================================================================
90 // TODO: make virtual
91 str config::toString() const {
92 switch (getType()) {
93 case Type_int:
94 return fmt ("%1", static_cast<const intconfig*> (this)->value);
95 break;
96
97 case Type_str:
98 return static_cast<const strconfig*> (this)->value;
99 break;
100
101 case Type_float:
102 return fmt ("%1", static_cast<const floatconfig*> (this)->value);
103 break;
104
105 case Type_bool:
106 return (static_cast<const boolconfig*> (this)->value) ? "true" : "false";
107 break;
108
109 case Type_keyseq:
110 return static_cast<const keyseqconfig*> (this)->value.toString();
111 break;
112
113 default:
114 break;
115 }
116
117 return "";
118 }
119
120 // =============================================================================
121 // Save the configuration to disk
122 bool config::save() {
123 QSettings* settings = getSettingsObject();
124 print ("Saving configuration to %1...\n", settings->fileName());
125
126 for (config* cfg : g_configPointers) {
127 if (!cfg)
158 break; 128 break;
159 129
160 case Type_str: 130 settings->setValue (cfg->name, cfg->toString());
161 valstring = static_cast<strconfig*> (cfg)->value;
162 break;
163
164 case Type_float:
165 valstring = fmt ("%1", static_cast<floatconfig*> (cfg)->value);
166 break;
167
168 case Type_bool:
169 valstring = (static_cast<boolconfig*> (cfg)->value) ? "true" : "false";
170 break;
171
172 case Type_keyseq:
173 valstring = static_cast<keyseqconfig*> (cfg)->value.toString();
174 break;
175
176 default:
177 break;
178 }
179
180 // Write the entry now.
181 fprint (f, "%1=%2\n", cfg->name, valstring);
182 } 131 }
183 132
184 f.close(); 133 settings->sync();
134 settings->deleteLater();
185 return true; 135 return true;
186 } 136 }
187 137
188 // ============================================================================= 138 // =============================================================================
189 void config::reset() { 139 void config::reset() {
194 cfg->resetValue(); 144 cfg->resetValue();
195 } 145 }
196 } 146 }
197 147
198 // ============================================================================= 148 // =============================================================================
199 str config::filepath() { 149 str config::filepath (str file) {
200 str path = fmt ("%1%2.cfg", dirpath(), str (APPNAME).toLower()); 150 return config::dirpath() + DIRSLASH + file;
201 return path;
202 } 151 }
203 152
204 // ============================================================================= 153 // =============================================================================
205 str config::dirpath() { 154 str config::dirpath() {
206 #ifndef _WIN32 155 QSettings* cfg = getSettingsObject();
207 return fmt ("%1" DIRSLASH ".%2" DIRSLASH, 156 return dirname (cfg->fileName());
208 QDir::homePath(), str (APPNAME).toLower());
209 #else
210 return fmt ("%1" DIRSLASH APPNAME DIRSLASH, QDir::homePath());
211 #endif // _WIN32
212 } 157 }
213 158
159 // =============================================================================
160 str config::defaultString() const {
161 str defstring = m_defstring;
162
163 // String types inevitably get extra quotes in their default string due to
164 // preprocessing stuff. We can only remove them now...
165 if (getType() == Type_str) {
166 defstring.remove (0, 1);
167 defstring.chop (1);
168 }
169
170 return defstring;
171 }
172
173 // =============================================================================
214 void addConfig (config* ptr) { 174 void addConfig (config* ptr) {
215 if (g_cfgPointerCursor == 0) 175 if (g_cfgPointerCursor == 0)
216 memset (g_configPointers, 0, sizeof g_configPointers); 176 memset (g_configPointers, 0, sizeof g_configPointers);
217 177
218 assert (g_cfgPointerCursor < MAX_CONFIG); 178 assert (g_cfgPointerCursor < MAX_CONFIG);

mercurial