| 1 /* |
1 /* |
| 2 * LDForge: LDraw parts authoring CAD |
2 * LDForge: LDraw parts authoring CAD |
| 3 * Copyright (C) 2013 Santeri Piippo |
3 * Copyright (C) 2013 Santeri Piippo |
| 4 * |
4 * |
| 5 * This program is free software: you can redistribute it and/or modify |
5 * This program is free software: you can redistribute it and/or modify |
| 6 * it under the terms of the GNU General Public License as published by |
6 * it under the terms of the GNU General Public License as published by |
| 7 * the Free Software Foundation, either version 3 of the License, or |
7 * the Free Software Foundation, either version 3 of the License, or |
| 8 * (at your option) any later version. |
8 * (at your option) any later version. |
| 9 * |
9 * |
| 10 * This program is distributed in the hope that it will be useful, |
10 * This program is distributed in the hope that it will be useful, |
| 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 * GNU General Public License for more details. |
13 * GNU General Public License for more details. |
| 14 * |
14 * |
| 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> |
20 #include <time.h> |
| 21 #include <QDir> |
21 #include <QDir> |
| 22 #include <qtextstream.h> |
22 #include <QTextStream> |
| 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 |
27 |
| 28 config* g_configPointers[MAX_CONFIG]; |
28 config* g_configPointers[MAX_CONFIG]; |
| 29 static ushort g_cfgPointerCursor = 0; |
29 static ushort g_cfgPointerCursor = 0; |
| 30 |
30 |
| 31 // ============================================================================= |
31 // ============================================================================= |
| 32 // Load the configuration from file |
32 // Load the configuration from file |
| 33 bool config::load () { |
33 bool config::load() |
| 34 print ("config::load: Loading configuration file...\n"); |
34 { |
| 35 print ("config::load: Path to configuration is %1\n", filepath ()); |
35 print( "config::load: Loading configuration file...\n" ); |
| |
36 print( "config::load: Path to configuration is %1\n", filepath() ); |
| 36 |
37 |
| 37 // Locale must be disabled for atof |
38 // Locale must be disabled for atof |
| 38 setlocale (LC_NUMERIC, "C"); |
39 setlocale( LC_NUMERIC, "C" ); |
| 39 |
40 |
| 40 File f (filepath (), File::Read); |
41 File f( filepath(), File::Read ); |
| 41 if (!f) |
42 int ln = 0; |
| |
43 |
| |
44 if( !f ) |
| 42 return false; |
45 return false; |
| 43 |
46 |
| 44 size_t ln = 0; |
|
| 45 |
|
| 46 // Read the values. |
47 // Read the values. |
| 47 for (str line : f) { |
48 for( str line : f ) |
| |
49 { |
| 48 ln++; |
50 ln++; |
| 49 |
51 |
| 50 if (line.isEmpty () || line[0] == '#') |
52 if( line.isEmpty() || line[0] == '#' ) |
| 51 continue; // Empty line or comment. |
53 continue; // Empty line or comment. |
| 52 |
54 |
| 53 // Find the equals sign. |
55 // Find the equals sign. |
| 54 int equals = line.indexOf ('='); |
56 int equals = line.indexOf( '=' ); |
| 55 if (equals == -1) { |
57 |
| 56 fprint (stderr, "couldn't find `=` sign in entry `%1`\n", line); |
58 if( equals == -1 ) |
| |
59 { |
| |
60 fprint( stderr, "couldn't find `=` sign in entry `%1`\n", line ); |
| 57 continue; |
61 continue; |
| 58 } |
62 } |
| 59 |
63 |
| 60 str entry = line.left (equals); |
64 str entry = line.left( equals ); |
| 61 str valstring = line.right (line.length () - equals - 1); |
65 str valstring = line.right( line.length() - equals - 1 ); |
| 62 |
66 |
| 63 // Find the config entry for this. |
67 // Find the config entry for this. |
| 64 config* cfg = null; |
68 config* cfg = null; |
| 65 for (config* i : g_configPointers) { |
69 |
| 66 if (!i) |
70 for( config* i : g_configPointers ) |
| |
71 { |
| |
72 if( !i ) |
| 67 break; |
73 break; |
| 68 |
74 |
| 69 if (entry == i->name) |
75 if( entry == i->name ) |
| 70 cfg = i; |
76 cfg = i; |
| 71 } |
77 } |
| 72 |
78 |
| 73 if (!cfg) { |
79 if( !cfg ) |
| 74 fprint (stderr, "unknown config `%1`\n", entry); |
80 { |
| |
81 fprint( stderr, "unknown config `%1`\n", entry ); |
| 75 continue; |
82 continue; |
| 76 } |
83 } |
| 77 |
84 |
| 78 switch (cfg->getType()) { |
85 switch( cfg->getType() ) |
| 79 case CONFIG_int: |
86 { |
| 80 static_cast<intconfig*> (cfg)->value = valstring.toInt (); |
87 case Type_int: |
| 81 break; |
88 static_cast<intconfig*>( cfg )->value = valstring.toInt(); |
| 82 |
89 break; |
| 83 case CONFIG_str: |
90 |
| 84 static_cast<strconfig*> (cfg)->value = valstring; |
91 case Type_str: |
| 85 break; |
92 static_cast<strconfig*>( cfg )->value = valstring; |
| 86 |
93 break; |
| 87 case CONFIG_float: |
94 |
| 88 static_cast<floatconfig*> (cfg)->value = valstring.toFloat (); |
95 case Type_float: |
| 89 break; |
96 static_cast<floatconfig*>( cfg )->value = valstring.toFloat(); |
| 90 |
97 break; |
| 91 case CONFIG_bool: |
98 |
| 92 { |
99 case Type_bool: |
| 93 bool& val = static_cast<boolconfig*> (cfg)->value; |
100 { |
| |
101 bool& val = static_cast<boolconfig*>( cfg )->value; |
| 94 |
102 |
| 95 if (valstring.toUpper () == "TRUE" || valstring == "1") |
103 if( valstring.toUpper() == "TRUE" || valstring == "1" ) |
| 96 val = true; |
104 val = true; |
| 97 elif (valstring.toUpper () == "FALSE" || valstring == "0") |
105 elif( valstring.toUpper() == "FALSE" || valstring == "0" ) |
| 98 val = false; |
106 val = false; |
| 99 break; |
107 |
| 100 } |
108 break; |
| 101 |
109 } |
| 102 case CONFIG_keyseq: |
110 |
| 103 static_cast<keyseqconfig*> (cfg)->value = keyseq::fromString (valstring); |
111 case Type_keyseq: |
| |
112 static_cast<keyseqconfig*>( cfg )->value = keyseq::fromString( valstring ); |
| 104 break; |
113 break; |
| 105 |
114 |
| 106 default: |
115 default: |
| 107 break; |
116 break; |
| 108 } |
117 } |
| 109 } |
118 } |
| 110 |
119 |
| 111 f.close (); |
120 f.close(); |
| 112 return true; |
121 return true; |
| 113 } |
122 } |
| 114 |
123 |
| 115 extern_cfg (str, io_ldpath); |
124 extern_cfg( str, io_ldpath ); |
| 116 |
125 |
| 117 // ============================================================================= |
126 // ============================================================================= |
| 118 // Save the configuration to disk |
127 // Save the configuration to disk |
| 119 bool config::save () { |
128 bool config::save() |
| |
129 { |
| 120 // The function will write floats, disable the locale now so that they |
130 // The function will write floats, disable the locale now so that they |
| 121 // are written properly. |
131 // are written properly. |
| 122 setlocale (LC_NUMERIC, "C"); |
132 setlocale( LC_NUMERIC, "C" ); |
| 123 |
133 |
| 124 // If the directory doesn't exist, create it now. |
134 // If the directory doesn't exist, create it now. |
| 125 if (QDir (dirpath ()).exists () == false) { |
135 if( QDir( dirpath() ).exists() == false ) |
| 126 fprint (stderr, "Creating config path %1...\n", dirpath ()); |
136 { |
| 127 if (!QDir ().mkpath (dirpath ())) { |
137 fprint( stderr, "Creating config path %1...\n", dirpath() ); |
| 128 critical ("Failed to create the configuration directory. Configuration cannot be saved!\n"); |
138 |
| |
139 if( !QDir().mkpath( dirpath() )) |
| |
140 { |
| |
141 critical( "Failed to create the configuration directory. Configuration cannot be saved!\n" ); |
| 129 return false; |
142 return false; |
| 130 } |
143 } |
| 131 } |
144 } |
| 132 |
145 |
| 133 File f (filepath (), File::Write); |
146 File f( filepath(), File::Write ); |
| 134 print ("writing cfg to %1\n", filepath ()); |
147 print( "writing cfg to %1\n", filepath() ); |
| 135 |
148 |
| 136 if (!f) { |
149 if( !f ) |
| |
150 { |
| 137 critical( fmt( QObject::tr( "Cannot save configuration, cannot open %1 for writing: %2\n" ), |
151 critical( fmt( QObject::tr( "Cannot save configuration, cannot open %1 for writing: %2\n" ), |
| 138 filepath(), strerror( errno ))); |
152 filepath(), strerror( errno )) ); |
| 139 return false; |
153 return false; |
| 140 } |
154 } |
| 141 |
155 |
| 142 fprint (f, "# Configuration file for " APPNAME "\n"); |
156 fprint( f, "# Configuration file for " APPNAME "\n" ); |
| 143 |
157 |
| 144 for (config* cfg : g_configPointers) { |
158 for( config * cfg : g_configPointers ) |
| 145 if (!cfg) |
159 { |
| 146 break; |
160 if( !cfg ) |
| 147 |
161 break; |
| 148 if (cfg->isDefault ()) |
162 |
| |
163 if( cfg->isDefault() ) |
| 149 continue; |
164 continue; |
| 150 |
165 |
| 151 str valstring; |
166 str valstring; |
| 152 switch (cfg->getType ()) { |
167 |
| 153 case CONFIG_int: |
168 switch( cfg->getType() ) |
| 154 valstring = fmt ("%1", static_cast<intconfig*> (cfg)->value); |
169 { |
| 155 break; |
170 case Type_int: |
| 156 |
171 valstring = fmt( "%1", static_cast<intconfig*>( cfg )->value ); |
| 157 case CONFIG_str: |
172 break; |
| 158 valstring = static_cast<strconfig*> (cfg)->value; |
173 |
| 159 break; |
174 case Type_str: |
| 160 |
175 valstring = static_cast<strconfig*>( cfg )->value; |
| 161 case CONFIG_float: |
176 break; |
| 162 valstring = fmt ("%1", static_cast<floatconfig*> (cfg)->value); |
177 |
| 163 break; |
178 case Type_float: |
| 164 |
179 valstring = fmt( "%1", static_cast<floatconfig*>( cfg )->value ); |
| 165 case CONFIG_bool: |
180 break; |
| 166 valstring = (static_cast<boolconfig*> (cfg)->value) ? "true" : "false"; |
181 |
| 167 break; |
182 case Type_bool: |
| 168 |
183 valstring = ( static_cast<boolconfig*>( cfg )->value ) ? "true" : "false"; |
| 169 case CONFIG_keyseq: |
184 break; |
| 170 valstring = static_cast<keyseqconfig*> (cfg)->value.toString (); |
185 |
| |
186 case Type_keyseq: |
| |
187 valstring = static_cast<keyseqconfig*>( cfg )->value.toString(); |
| 171 break; |
188 break; |
| 172 |
189 |
| 173 default: |
190 default: |
| 174 break; |
191 break; |
| 175 } |
192 } |
| 176 |
193 |
| 177 // Write the entry now. |
194 // Write the entry now. |
| 178 fprint (f, "%1=%2\n", cfg->name, valstring); |
195 fprint( f, "%1=%2\n", cfg->name, valstring ); |
| 179 } |
196 } |
| 180 |
197 |
| 181 f.close (); |
198 f.close(); |
| 182 return true; |
199 return true; |
| 183 } |
200 } |
| 184 |
201 |
| 185 // ============================================================================= |
202 // ============================================================================= |
| 186 void config::reset () { |
203 void config::reset() |
| 187 for (config* cfg : g_configPointers) { |
204 { |
| 188 if (!cfg) |
205 for( config * cfg : g_configPointers ) |
| 189 break; |
206 { |
| 190 |
207 if( !cfg ) |
| 191 cfg->resetValue (); |
208 break; |
| 192 } |
209 |
| 193 } |
210 cfg->resetValue(); |
| 194 |
211 } |
| 195 // ============================================================================= |
212 } |
| 196 str config::filepath () { |
213 |
| 197 str path = fmt ("%1%2.cfg", dirpath (), |
214 // ============================================================================= |
| 198 str (APPNAME).toLower ()); |
215 str config::filepath() |
| |
216 { |
| |
217 str path = fmt( "%1%2.cfg", dirpath(), |
| |
218 str( APPNAME ).toLower() ); |
| 199 return path; |
219 return path; |
| 200 } |
220 } |
| 201 |
221 |
| 202 // ============================================================================= |
222 // ============================================================================= |
| 203 str config::dirpath () { |
223 str config::dirpath() |
| |
224 { |
| 204 #ifndef _WIN32 |
225 #ifndef _WIN32 |
| 205 return fmt ("%1" DIRSLASH ".%2" DIRSLASH, |
226 return fmt( "%1" DIRSLASH ".%2" DIRSLASH, |
| 206 QDir::homePath (), str (APPNAME).toLower ()); |
227 QDir::homePath(), str( APPNAME ).toLower() ); |
| 207 #else |
228 #else |
| 208 return fmt ("%1" DIRSLASH APPNAME DIRSLASH, QDir::homePath ()); |
229 return fmt( "%1" DIRSLASH APPNAME DIRSLASH, QDir::homePath() ); |
| 209 #endif // _WIN32 |
230 #endif // _WIN32 |
| 210 } |
231 } |
| 211 |
232 |
| 212 void addConfig (config* ptr) { |
233 void addConfig( config* ptr ) |
| 213 if (g_cfgPointerCursor == 0) |
234 { |
| 214 memset (g_configPointers, 0, sizeof g_configPointers); |
235 if( g_cfgPointerCursor == 0 ) |
| 215 |
236 memset( g_configPointers, 0, sizeof g_configPointers ); |
| 216 assert (g_cfgPointerCursor < MAX_CONFIG); |
237 |
| |
238 assert( g_cfgPointerCursor < MAX_CONFIG ); |
| 217 g_configPointers[g_cfgPointerCursor++] = ptr; |
239 g_configPointers[g_cfgPointerCursor++] = ptr; |
| 218 } |
240 } |