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 } |