]>
Commit | Line | Data |
---|---|---|
1 | /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ | |
2 | /* | |
3 | * viking -- GPS Data and Topo Analyzer, Explorer, and Manager | |
4 | * | |
5 | * Copyright (C) 2013, Rob Norris <rw_norris@hotmail.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | * | |
21 | */ | |
22 | /* | |
23 | * Sort of like the globals file, but values are automatically saved via program use. | |
24 | * Some settings are *not* intended to have any GUI controls. | |
25 | * Other settings be can used to set other GUI elements. | |
26 | * | |
27 | * ATM This is implemented using the simple (for me!) GKeyFile API - AKA an .ini file | |
28 | * One might wish to consider the more modern alternative such as: | |
29 | * http://developer.gnome.org/gio/2.26/GSettings.html | |
30 | * Since these settings are 'internal' I have no problem with them *not* being supported | |
31 | * between various Viking versions, should one switch to different API/storage methods. | |
32 | * Indeed even the internal settings themselves can be liable to change. | |
33 | */ | |
34 | #include <glib.h> | |
35 | #include "dir.h" | |
36 | ||
37 | static GKeyFile *keyfile; | |
38 | ||
39 | #define VIKING_INI_FILE "viking.ini" | |
40 | ||
41 | static gboolean settings_load_from_file() | |
42 | { | |
43 | GKeyFileFlags flags = G_KEY_FILE_KEEP_COMMENTS; | |
44 | ||
45 | GError *error = NULL; | |
46 | ||
47 | gchar *fn = g_build_filename ( a_get_viking_dir(), VIKING_INI_FILE, NULL ); | |
48 | ||
49 | if ( !g_key_file_load_from_file ( keyfile, fn, flags, &error ) ) { | |
50 | g_warning ( "%s: %s", error->message, fn ); | |
51 | g_free ( fn ); | |
52 | g_error_free ( error ); | |
53 | return FALSE; | |
54 | } | |
55 | ||
56 | g_free ( fn ); | |
57 | ||
58 | return TRUE; | |
59 | } | |
60 | ||
61 | void a_settings_init() | |
62 | { | |
63 | keyfile = g_key_file_new(); | |
64 | settings_load_from_file(); | |
65 | } | |
66 | ||
67 | /** | |
68 | * a_settings_uninit: | |
69 | * | |
70 | * ATM: The only time settings are saved is on program exit | |
71 | * Could change this to occur on window exit or dialog exit or have memory hash of values...? | |
72 | */ | |
73 | void a_settings_uninit() | |
74 | { | |
75 | GError *error = NULL; | |
76 | gchar *fn = g_build_filename ( a_get_viking_dir(), VIKING_INI_FILE, NULL ); | |
77 | gsize size; | |
78 | ||
79 | gchar *keyfilestr = g_key_file_to_data ( keyfile, &size, &error ); | |
80 | ||
81 | if ( error ) { | |
82 | g_warning ( "%s", error->message ); | |
83 | g_error_free ( error ); | |
84 | goto tidy; | |
85 | } | |
86 | ||
87 | g_file_set_contents ( fn, keyfilestr, size, &error ); | |
88 | if ( error ) { | |
89 | g_warning ( "%s: %s", error->message, fn ); | |
90 | g_error_free ( error ); | |
91 | } | |
92 | ||
93 | g_key_file_free ( keyfile ); | |
94 | tidy: | |
95 | g_free ( keyfilestr ); | |
96 | g_free ( fn ); | |
97 | } | |
98 | ||
99 | // ATM, can't see a point in having any more than one group for various settings | |
100 | #define VIKING_SETTINGS_GROUP "viking" | |
101 | ||
102 | static gboolean settings_get_boolean ( const gchar *group, const gchar *name, gboolean *val ) | |
103 | { | |
104 | GError *error = NULL; | |
105 | gboolean success = TRUE; | |
106 | gboolean bb = g_key_file_get_boolean ( keyfile, group, name, &error ); | |
107 | if ( error ) { | |
108 | // Only print on debug - as often may have requests for keys not in the file | |
109 | g_debug ( "%s", error->message ); | |
110 | g_error_free ( error ); | |
111 | success = FALSE; | |
112 | } | |
113 | *val = bb; | |
114 | return success; | |
115 | } | |
116 | ||
117 | gboolean a_settings_get_boolean ( const gchar *name, gboolean *val ) | |
118 | { | |
119 | return settings_get_boolean ( VIKING_SETTINGS_GROUP, name, val ); | |
120 | } | |
121 | ||
122 | void a_settings_set_boolean ( const gchar *name, gboolean val ) | |
123 | { | |
124 | g_key_file_set_boolean ( keyfile, VIKING_SETTINGS_GROUP, name, val ); | |
125 | } | |
126 | ||
127 | static gboolean settings_get_string ( const gchar *group, const gchar *name, gchar **val ) | |
128 | { | |
129 | GError *error = NULL; | |
130 | gboolean success = TRUE; | |
131 | gchar *str = g_key_file_get_string ( keyfile, group, name, &error ); | |
132 | if ( error ) { | |
133 | // Only print on debug - as often may have requests for keys not in the file | |
134 | g_debug ( "%s", error->message ); | |
135 | g_error_free ( error ); | |
136 | success = FALSE; | |
137 | } | |
138 | *val = str; | |
139 | return success; | |
140 | } | |
141 | ||
142 | gboolean a_settings_get_string ( const gchar *name, gchar **val ) | |
143 | { | |
144 | return settings_get_string ( VIKING_SETTINGS_GROUP, name, val ); | |
145 | } | |
146 | ||
147 | void a_settings_set_string ( const gchar *name, const gchar *val ) | |
148 | { | |
149 | g_key_file_set_string ( keyfile, VIKING_SETTINGS_GROUP, name, val ); | |
150 | } | |
151 | ||
152 | static gboolean settings_get_integer ( const gchar *group, const gchar *name, gint *val ) | |
153 | { | |
154 | GError *error = NULL; | |
155 | gboolean success = TRUE; | |
156 | gint ii = g_key_file_get_integer ( keyfile, group, name, &error ); | |
157 | if ( error ) { | |
158 | // Only print on debug - as often may have requests for keys not in the file | |
159 | g_debug ( "%s", error->message ); | |
160 | g_error_free ( error ); | |
161 | success = FALSE; | |
162 | } | |
163 | *val = ii; | |
164 | return success; | |
165 | } | |
166 | ||
167 | gboolean a_settings_get_integer ( const gchar *name, gint *val ) | |
168 | { | |
169 | return settings_get_integer ( VIKING_SETTINGS_GROUP, name, val ); | |
170 | } | |
171 | ||
172 | void a_settings_set_integer ( const gchar *name, gint val ) | |
173 | { | |
174 | g_key_file_set_integer ( keyfile, VIKING_SETTINGS_GROUP, name, val ); | |
175 | } | |
176 | ||
177 | static gboolean settings_get_double ( const gchar *group, const gchar *name, gdouble *val ) | |
178 | { | |
179 | GError *error = NULL; | |
180 | gboolean success = TRUE; | |
181 | gdouble dd = g_key_file_get_double ( keyfile, group, name, &error ); | |
182 | if ( error ) { | |
183 | // Only print on debug - as often may have requests for keys not in the file | |
184 | g_debug ( "%s", error->message ); | |
185 | g_error_free ( error ); | |
186 | success = FALSE; | |
187 | } | |
188 | *val = dd; | |
189 | return success; | |
190 | } | |
191 | ||
192 | gboolean a_settings_get_double ( const gchar *name, gdouble *val ) | |
193 | { | |
194 | return settings_get_double ( VIKING_SETTINGS_GROUP, name, val ); | |
195 | } | |
196 | ||
197 | void a_settings_set_double ( const gchar *name, gdouble val ) | |
198 | { | |
199 | g_key_file_set_double ( keyfile, VIKING_SETTINGS_GROUP, name, val ); | |
200 | } | |
201 | ||
202 | static gboolean settings_get_integer_list ( const gchar *group, const gchar *name, gint **vals, gsize *length ) | |
203 | { | |
204 | GError *error = NULL; | |
205 | gboolean success = TRUE; | |
206 | gint *ints = g_key_file_get_integer_list ( keyfile, group, name, length, &error ); | |
207 | if ( error ) { | |
208 | // Only print on debug - as often may have requests for keys not in the file | |
209 | g_debug ( "%s", error->message ); | |
210 | g_error_free ( error ); | |
211 | success = FALSE; | |
212 | } | |
213 | *vals = ints; | |
214 | return success; | |
215 | } | |
216 | ||
217 | /* | |
218 | * The returned list of integers should be freed when no longer needed | |
219 | */ | |
220 | static gboolean a_settings_get_integer_list ( const gchar *name, gint **vals, gsize* length ) | |
221 | { | |
222 | return settings_get_integer_list ( VIKING_SETTINGS_GROUP, name, vals, length ); | |
223 | } | |
224 | ||
225 | static void a_settings_set_integer_list ( const gchar *name, gint vals[], gsize length ) | |
226 | { | |
227 | g_key_file_set_integer_list ( keyfile, VIKING_SETTINGS_GROUP, name, vals, length ); | |
228 | } | |
229 | ||
230 | gboolean a_settings_get_integer_list_contains ( const gchar *name, gint val ) | |
231 | { | |
232 | gint* vals = NULL; | |
233 | gsize length; | |
234 | // Get current list and see if the value supplied is in the list | |
235 | gboolean contains = FALSE; | |
236 | // Get current list | |
237 | if ( a_settings_get_integer_list ( name, &vals, &length ) ) { | |
238 | // See if it's not already there | |
239 | gint ii = 0; | |
240 | if ( vals && length ) { | |
241 | while ( ii < length ) { | |
242 | if ( vals[ii] == val ) { | |
243 | contains = TRUE; | |
244 | break; | |
245 | } | |
246 | ii++; | |
247 | } | |
248 | // Free old array | |
249 | g_free (vals); | |
250 | } | |
251 | } | |
252 | return contains; | |
253 | } | |
254 | ||
255 | void a_settings_set_integer_list_containing ( const gchar *name, gint val ) | |
256 | { | |
257 | gint* vals = NULL; | |
258 | gsize length; | |
259 | gboolean need_to_add = TRUE; | |
260 | gint ii = 0; | |
261 | // Get current list | |
262 | if ( a_settings_get_integer_list ( name, &vals, &length ) ) { | |
263 | // See if it's not already there | |
264 | if ( vals && length ) { | |
265 | while ( ii < length ) { | |
266 | if ( vals[ii] == val ) { | |
267 | need_to_add = FALSE; | |
268 | break; | |
269 | } | |
270 | ii++; | |
271 | } | |
272 | } | |
273 | } | |
274 | // Add value into array if necessary | |
275 | if ( need_to_add ) { | |
276 | // NB not bothering to sort this 'list' ATM as there is not much to be gained | |
277 | guint new_length = length + 1; | |
278 | gint new_vals[new_length]; | |
279 | // Copy array | |
280 | for ( ii = 0; ii < length; ii++ ) { | |
281 | new_vals[ii] = vals[ii]; | |
282 | } | |
283 | new_vals[length] = val; // Set the new value | |
284 | // Apply | |
285 | a_settings_set_integer_list ( name, new_vals, new_length ); | |
286 | // Free old array | |
287 | g_free (vals); | |
288 | } | |
289 | } |