1 #include <stdlib.h>
2 #include <glib/gprintf.h>
3 #include "MakerDialogUtil.h"
4 #include "MakerDialogProperty.h"
5 
6 /*============================================
7  * PropertyContext Methods
8  */
9 
property_context_default(PropertyContext * ctx)10 void property_context_default(PropertyContext * ctx)
11 {
12     if (ctx->spec->defaultValue == NULL)
13 	return;
14     mkdg_log(DEBUG, "property_context_default(%s)", ctx->spec->key);
15     gboolean ret =
16 	property_context_from_string(ctx, ctx->spec->defaultValue);
17     if (!ret) {
18 	mkdg_log(WARN,
19 		 "property_context_default(%s): failed to convert string %s, return NULL",
20 		 ctx->spec->key, ctx->spec->defaultValue);
21     }
22 }
23 
property_context_new(MkdgPropertySpec * spec,MkdgBackend * backend,gpointer parent,gpointer auxData)24 PropertyContext *property_context_new(MkdgPropertySpec * spec,
25 				      MkdgBackend * backend,
26 				      gpointer parent, gpointer auxData)
27 {
28     if (spec == NULL) {
29 	return NULL;
30     }
31     mkdg_log(INFO, "property_context_new(%s,-,-,-)", spec->key);
32     PropertyContext *ctx = g_new0(PropertyContext, 1);
33     ctx->spec = spec;
34     ctx->backend = backend;
35     ctx->parent = parent;
36     ctx->auxData = auxData;
37     g_value_init(&(ctx->value), ctx->spec->valueType);
38     if (ctx->backend != NULL) {
39 	GValue *value = property_context_read(ctx, NULL);
40 	if (value == NULL) {
41 	    property_context_default(ctx);
42 	}
43     } else {
44 	property_context_default(ctx);
45     }
46     mkdg_log(DEBUG, "property_context_new(%s):Done", ctx->spec->key);
47     return ctx;
48 }
49 
property_context_to_string(PropertyContext * ctx)50 gchar *property_context_to_string(PropertyContext * ctx)
51 {
52     if (ctx == NULL) {
53 	return NULL;
54     }
55     return mkdg_g_value_to_string(&(ctx->value));
56 }
57 
property_context_from_string(PropertyContext * ctx,const gchar * str)58 gboolean property_context_from_string(PropertyContext * ctx,
59 				      const gchar * str)
60 {
61     if (ctx == NULL) {
62 	return FALSE;
63     }
64     return mkdg_g_value_from_string(&(ctx->value), str);
65 }
66 
property_context_from_gvalue(PropertyContext * ctx,GValue * value)67 gboolean property_context_from_gvalue(PropertyContext * ctx,
68 				      GValue * value)
69 {
70     if (ctx == NULL) {
71 	return FALSE;
72     }
73     if (!G_IS_VALUE(value)) {
74 	return FALSE;
75     }
76     g_value_copy(value, &(ctx->value));
77     return TRUE;
78 }
79 
80 /* read: backend -> Context */
81 /* write: Context -> backend */
82 /* get: Context -> GValue */
83 /* set: GValue -> Context */
84 /* load: read then get, errors in read are ignored */
85 /* save: set then write */
86 /* apply: Context -> apply callback */
87 /* use: load then apply */
88 /* assign: save then apply */
property_context_read(PropertyContext * ctx,gpointer userData)89 GValue *property_context_read(PropertyContext * ctx, gpointer userData)
90 {
91     if (ctx == NULL) {
92 	return NULL;
93     }
94     mkdg_log(DEBUG, "property_context_read(%s,-)", ctx->spec->key);
95     if (mkdg_has_flag
96 	(ctx->spec->propertyFlags, MKDG_PROPERTY_FLAG_NO_BACKEND)) {
97 	return NULL;
98     }
99     if (ctx->backend == NULL) {
100 	return NULL;
101     }
102     GValue *result = mkdg_backend_read(ctx->backend, &(ctx->value),
103 				       ctx->spec->subSection,
104 				       ctx->spec->key, userData);
105 
106     if (result == NULL) {
107 	mkdg_log(WARN, "property_context_read(%s): failed to read key",
108 		 ctx->spec->key);
109     }
110     return result;
111 }
112 
property_context_write(PropertyContext * ctx,gpointer userData)113 gboolean property_context_write(PropertyContext * ctx, gpointer userData)
114 {
115     if (ctx == NULL) {
116 	return FALSE;
117     }
118     mkdg_log(DEBUG, "property_context_read(%s,-)", ctx->spec->key);
119     if (mkdg_has_flag
120 	(ctx->spec->propertyFlags, MKDG_PROPERTY_FLAG_NO_BACKEND)) {
121 	return FALSE;
122     }
123     if (ctx->backend == NULL) {
124 	return FALSE;
125     }
126     return ctx->backend->writeFunc(ctx->backend, &(ctx->value),
127 				   ctx->spec->subSection, ctx->spec->key,
128 				   userData);
129 }
130 
property_context_get(PropertyContext * ctx)131 GValue *property_context_get(PropertyContext * ctx)
132 {
133     if (ctx == NULL) {
134 	mkdg_log(WARN, "property_context_get(-): ctx is NULL");
135 	return NULL;
136     }
137     mkdg_log(DEBUG, "property_context_get(%s): value=%s",
138 	     ctx->spec->key, mkdg_g_value_to_string(&(ctx->value)));
139     return &(ctx->value);
140 }
141 
property_context_set(PropertyContext * ctx,GValue * value)142 gboolean property_context_set(PropertyContext * ctx, GValue * value)
143 {
144     if (ctx == NULL) {
145 	mkdg_log(WARN, "property_context_set(-): ctx is NULL");
146 	return FALSE;
147     }
148     if (!G_IS_VALUE(value)) {
149 	mkdg_log(WARN, "property_context_set(%s): value is not GValue",
150 		 ctx->spec->key);
151 	return FALSE;
152     }
153     mkdg_log(DEBUG, "property_context_set(%s,%s)", ctx->spec->key,
154 	     mkdg_g_value_to_string(value));
155     g_value_copy(value, &(ctx->value));
156     return TRUE;
157 }
158 
property_context_load(PropertyContext * ctx,gpointer userData)159 GValue *property_context_load(PropertyContext * ctx, gpointer userData)
160 {
161     mkdg_log(DEBUG, "property_context_load(%s,-)", ctx->spec->key);
162     property_context_read(ctx, userData);
163     return property_context_get(ctx);
164 }
165 
property_context_save(PropertyContext * ctx,GValue * value,gpointer userData)166 gboolean property_context_save(PropertyContext * ctx, GValue * value,
167 			       gpointer userData)
168 {
169     mkdg_log(DEBUG, "property_context_save(%s,-)", ctx->spec->key);
170     if (!property_context_set(ctx, value)) {
171 	return FALSE;
172     }
173     return property_context_write(ctx, userData);
174 }
175 
property_context_apply(PropertyContext * ctx,gpointer userData)176 gboolean property_context_apply(PropertyContext * ctx, gpointer userData)
177 {
178     if (ctx == NULL || ctx->parent == NULL) {
179 	mkdg_log(WARN,
180 		 "property_context_apply(%s): either ctx or ctx->parent is NULL",
181 		 ctx->spec->key);
182 	return FALSE;
183     }
184     if (ctx->spec->applyFunc == NULL ){
185 	mkdg_log(DEBUG, "property_context_apply(%s,-): No apply function, skip", ctx->spec->key);
186 	return TRUE;
187     }
188     mkdg_log(DEBUG, "property_context_apply(%s,-): value %s",
189 	     ctx->spec->key, mkdg_g_value_to_string(&(ctx->value)));
190     return ctx->spec->applyFunc(ctx, userData);
191 }
192 
property_context_use(PropertyContext * ctx,gpointer userData)193 gboolean property_context_use(PropertyContext * ctx, gpointer userData)
194 {
195     mkdg_log(DEBUG, "property_context_use(%s,-)", ctx->spec->key);
196     GValue *ret = property_context_load(ctx, userData);
197     if (ret == NULL) {
198 	mkdg_log(WARN,
199 		 "property_context_use(%s): property_context_load return NULL",
200 		 ctx->spec->key);
201 	return FALSE;
202     }
203     return property_context_apply(ctx, userData);
204 }
205 
property_context_free(PropertyContext * ctx)206 void property_context_free(PropertyContext * ctx)
207 {
208     mkdg_log(INFO, "property_context_free(%s,-)", ctx->spec->key);
209     g_value_unset(&(ctx->value));
210     g_free(ctx);
211 }
212 
213 
214 /*============================================
215  * MkdgProperties Methods
216  */
217 
218 /* This alone is sufficient to generate schemas */
mkdg_properties_from_spec_array(MkdgPropertySpec specs[],MkdgBackend * backend,gpointer parent,gpointer auxData)219 MkdgProperties *mkdg_properties_from_spec_array(MkdgPropertySpec specs[],
220 						MkdgBackend * backend,
221 						gpointer parent,
222 						gpointer auxData)
223 {
224     gsize arraySize = 0;
225     gsize i;
226     for (i = 0; specs[i].valueType != G_TYPE_INVALID; i++) {
227 	arraySize++;
228     }
229     MkdgProperties *result = g_new0(MkdgProperties, 1);
230     result->backend = backend;
231     result->contexts = g_ptr_array_sized_new(arraySize);
232     result->auxData = auxData;
233     for (i = 0; i < arraySize; i++) {
234 	PropertyContext *ctx = property_context_new(&specs[i], backend,
235 						    parent, auxData);
236 	g_ptr_array_add(result->contexts, (gpointer) ctx);
237     }
238     return result;
239 }
240 
mkdg_properties_find_by_key(MkdgProperties * properties,const gchar * key)241 PropertyContext *mkdg_properties_find_by_key(MkdgProperties * properties,
242 					     const gchar * key)
243 {
244     gsize i;
245     for (i = 0; i < mkdg_properties_size(properties); i++) {
246 	PropertyContext *ctx = mkdg_properties_index(properties, i);
247 	if (STRING_EQUALS(ctx->spec->key, key)) {
248 	    return ctx;
249 	}
250     }
251     return NULL;
252 }
253 
mkdg_properties_index(MkdgProperties * properties,guint index)254 PropertyContext *mkdg_properties_index(MkdgProperties *
255 				       properties, guint index)
256 {
257     return (PropertyContext *)
258 	g_ptr_array_index(properties->contexts, index);
259 }
260 
mkdg_properties_get_by_key(MkdgProperties * properties,const gchar * key)261 GValue *mkdg_properties_get_by_key(MkdgProperties * properties,
262 				   const gchar * key)
263 {
264     if (properties == NULL) {
265 	return NULL;
266     }
267     PropertyContext *ctx = mkdg_properties_find_by_key(properties, key);
268     return property_context_get(ctx);
269 }
270 
mkdg_properties_set_by_key(MkdgProperties * properties,const gchar * key,GValue * value)271 gboolean mkdg_properties_set_by_key(MkdgProperties * properties,
272 				    const gchar * key, GValue * value)
273 {
274     if (properties == NULL) {
275 	return FALSE;
276     }
277     PropertyContext *ctx = mkdg_properties_find_by_key(properties, key);
278     return property_context_set(ctx, value);
279 }
280 
mkdg_properties_set_boolean_by_key(MkdgProperties * properties,const gchar * key,gboolean boolValue)281 gboolean mkdg_properties_set_boolean_by_key(MkdgProperties * properties,
282 					    const gchar * key,
283 					    gboolean boolValue)
284 {
285     GValue gValue = { 0 };
286     g_value_init(&gValue, G_TYPE_BOOLEAN);
287     g_value_set_boolean(&gValue, boolValue);
288     gboolean result = mkdg_properties_set_by_key(properties, key, &gValue);
289     g_value_unset(&gValue);
290     return result;
291 }
292 
mkdg_properties_set_int_by_key(MkdgProperties * properties,const gchar * key,gint intValue)293 gboolean mkdg_properties_set_int_by_key(MkdgProperties * properties,
294 					const gchar * key, gint intValue)
295 {
296     GValue gValue = { 0 };
297     g_value_init(&gValue, G_TYPE_INT);
298     g_value_set_int(&gValue, intValue);
299     gboolean result = mkdg_properties_set_by_key(properties, key, &gValue);
300     g_value_unset(&gValue);
301     return result;
302 }
303 
mkdg_properties_set_string_by_key(MkdgProperties * properties,const gchar * key,const gchar * stringValue)304 gboolean mkdg_properties_set_string_by_key(MkdgProperties * properties,
305 					   const gchar * key,
306 					   const gchar * stringValue)
307 {
308     GValue gValue = { 0 };
309     g_value_init(&gValue, G_TYPE_STRING);
310     g_value_set_string(&gValue, stringValue);
311     gboolean result = mkdg_properties_set_by_key(properties, key, &gValue);
312     g_value_unset(&gValue);
313     return result;
314 }
315 
mkdg_properties_load_by_key(MkdgProperties * properties,const gchar * key,gpointer userData)316 GValue *mkdg_properties_load_by_key(MkdgProperties * properties,
317 				    const gchar * key, gpointer userData)
318 {
319     if (properties == NULL) {
320 	return NULL;
321     }
322     PropertyContext *ctx = mkdg_properties_find_by_key(properties, key);
323     return property_context_load(ctx, userData);
324 }
325 
mkdg_properties_save_by_key(MkdgProperties * properties,const gchar * key,GValue * value,gpointer userData)326 gboolean mkdg_properties_save_by_key(MkdgProperties * properties,
327 				     const gchar * key, GValue * value,
328 				     gpointer userData)
329 {
330     if (properties == NULL) {
331 	return FALSE;
332     }
333     PropertyContext *ctx = mkdg_properties_find_by_key(properties, key);
334     return property_context_save(ctx, value, userData);
335 }
336 
mkdg_properties_save_boolean_by_key(MkdgProperties * properties,const gchar * key,gboolean boolValue,gpointer userData)337 gboolean mkdg_properties_save_boolean_by_key(MkdgProperties * properties,
338 					     const gchar * key,
339 					     gboolean boolValue,
340 					     gpointer userData)
341 {
342     GValue gValue = { 0 };
343     g_value_init(&gValue, G_TYPE_BOOLEAN);
344     g_value_set_boolean(&gValue, boolValue);
345     gboolean result =
346 	mkdg_properties_save_by_key(properties, key, &gValue, userData);
347     g_value_unset(&gValue);
348     return result;
349 }
350 
mkdg_properties_save_int_by_key(MkdgProperties * properties,const gchar * key,gint intValue,gpointer userData)351 gboolean mkdg_properties_save_int_by_key(MkdgProperties * properties,
352 					 const gchar * key, gint intValue,
353 					 gpointer userData)
354 {
355     GValue gValue = { 0 };
356     g_value_init(&gValue, G_TYPE_INT);
357     g_value_set_int(&gValue, intValue);
358     gboolean result =
359 	mkdg_properties_save_by_key(properties, key, &gValue, userData);
360     g_value_unset(&gValue);
361     return result;
362 }
363 
mkdg_properties_save_string_by_key(MkdgProperties * properties,const gchar * key,const gchar * stringValue,gpointer userData)364 gboolean mkdg_properties_save_string_by_key(MkdgProperties * properties,
365 					    const gchar * key,
366 					    const gchar * stringValue,
367 					    gpointer userData)
368 {
369     GValue gValue = { 0 };
370     g_value_init(&gValue, G_TYPE_STRING);
371     g_value_set_string(&gValue, stringValue);
372     gboolean result =
373 	mkdg_properties_save_by_key(properties, key, &gValue, userData);
374     g_value_unset(&gValue);
375     return result;
376 }
377 
mkdg_properties_apply_by_key(MkdgProperties * properties,const gchar * key,gpointer userData)378 gboolean mkdg_properties_apply_by_key(MkdgProperties * properties,
379 				      const gchar * key, gpointer userData)
380 {
381     if (properties == NULL) {
382 	return FALSE;
383     }
384     PropertyContext *ctx = mkdg_properties_find_by_key(properties, key);
385     return property_context_apply(ctx, userData);
386 }
387 
mkdg_properties_size(MkdgProperties * properties)388 gsize mkdg_properties_size(MkdgProperties * properties)
389 {
390     return properties->contexts->len;
391 }
392 
393 /* For setup interface */
mkdg_properties_load_all(MkdgProperties * properties,gpointer userData)394 gboolean mkdg_properties_load_all(MkdgProperties * properties,
395 				  gpointer userData)
396 {
397     gsize i;
398     gboolean result = TRUE;
399     for (i = 0; i < mkdg_properties_size(properties); i++) {
400 	PropertyContext *ctx = mkdg_properties_index(properties, i);
401 	GValue *value = property_context_load(ctx, userData);
402 	if (value == NULL) {
403 	    result = FALSE;
404 	}
405     }
406     return result;
407 }
408 
mkdg_properties_write_all(MkdgProperties * properties,gpointer userData)409 gboolean mkdg_properties_write_all(MkdgProperties * properties,
410 				   gpointer userData)
411 {
412     gsize i;
413     gboolean result = TRUE;
414     for (i = 0; i < mkdg_properties_size(properties); i++) {
415 	PropertyContext *ctx = mkdg_properties_index(properties, i);
416 	gboolean ret = property_context_write(ctx, userData);
417 	if (!ret) {
418 	    result = FALSE;
419 	}
420     }
421     return result;
422 }
423 
424 /* For actual runtime */
mkdg_properties_apply_all(MkdgProperties * properties,gpointer userData)425 gboolean mkdg_properties_apply_all(MkdgProperties * properties,
426 				   gpointer userData)
427 {
428     gsize i;
429     gboolean result = TRUE;
430     for (i = 0; i < mkdg_properties_size(properties); i++) {
431 	PropertyContext *ctx = mkdg_properties_index(properties, i);
432 	gboolean ret = property_context_apply(ctx, userData);
433 	if (!ret) {
434 	    result = FALSE;
435 	}
436     }
437     return result;
438 }
439 
mkdg_properties_use_all(MkdgProperties * properties,gpointer userData)440 gboolean mkdg_properties_use_all(MkdgProperties * properties,
441 				 gpointer userData)
442 {
443     gsize i;
444     gboolean result = TRUE;
445     for (i = 0; i < mkdg_properties_size(properties); i++) {
446 	PropertyContext *ctx = mkdg_properties_index(properties, i);
447 	gboolean ret = property_context_use(ctx, userData);
448 	if (!ret) {
449 	    result = FALSE;
450 	}
451     }
452     return result;
453 }
454 
mkdg_properties_free(MkdgProperties * properties)455 void mkdg_properties_free(MkdgProperties * properties)
456 {
457     gsize i;
458     for (i = 0; i < mkdg_properties_size(properties); i++) {
459 	PropertyContext *ctx = mkdg_properties_index(properties, i);
460 	property_context_free(ctx);
461     }
462     g_ptr_array_free(properties->contexts, TRUE);
463     g_free(properties);
464 }
465