1 /*
2  * Copyright © 2014  Red Hat, Inc. All rights reserved.
3  * Copyright © 2014  Ding-Yi Chen <dchen@redhat.com>
4  *
5  * This file is part of the ibus-chewing Project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  */
21 
22 #include <ibus.h>
23 #include <glib.h>
24 #include "MakerDialogUtil.h"
25 #include "GSettingsBackend.h"
26 
mkdg_g_variant_type_string(GType gType)27 const gchar *mkdg_g_variant_type_string(GType gType)
28 {
29     switch (gType) {
30     case G_TYPE_BOOLEAN:
31 	return (const gchar *) G_VARIANT_TYPE_BOOLEAN;
32     case G_TYPE_UINT:
33 	return (const gchar *) G_VARIANT_TYPE_UINT32;
34     case G_TYPE_UINT64:
35 	return (const gchar *) G_VARIANT_TYPE_UINT64;
36     case G_TYPE_INT:
37 	return (const gchar *) G_VARIANT_TYPE_INT32;
38     case G_TYPE_INT64:
39 	return (const gchar *) G_VARIANT_TYPE_INT64;
40     case G_TYPE_STRING:
41 	return (const gchar *) G_VARIANT_TYPE_STRING;
42     default:
43 	break;
44     }
45     return NULL;
46 }
47 
mkdg_g_settings_attr_append(gchar * buf,gint bufferSize,const gchar * attr,const gchar * value)48 gchar *mkdg_g_settings_attr_append(gchar * buf, gint bufferSize,
49 				   const gchar * attr, const gchar * value)
50 {
51     if (STRING_IS_EMPTY(attr))
52 	return buf;
53     if (!STRING_IS_EMPTY(buf))
54 	g_strlcat(buf, " ", bufferSize);
55 
56     return buf;
57 }
58 
mkdg_g_variant_to_string(GVariant * gVar)59 gchar *mkdg_g_variant_to_string(GVariant * gVar)
60 {
61     static gchar result[MAKER_DIALOG_VALUE_LENGTH];
62     result[0] = '\0';
63     const GVariantType *gVType = g_variant_get_type(gVar);
64     if (g_variant_type_is_subtype_of(gVType, G_VARIANT_TYPE_BOOLEAN)) {
65 	g_snprintf(result, MAKER_DIALOG_VALUE_LENGTH,
66 		   g_variant_get_boolean(gVar) ? "1" : "0");
67     } else if (g_variant_type_is_subtype_of(gVType, G_VARIANT_TYPE_UINT16)) {
68 	g_snprintf(result, MAKER_DIALOG_VALUE_LENGTH, "%" G_GUINT16_FORMAT,
69 		   g_variant_get_uint16(gVar));
70     } else if (g_variant_type_is_subtype_of(gVType, G_VARIANT_TYPE_UINT32)) {
71 	g_snprintf(result, MAKER_DIALOG_VALUE_LENGTH, "%" G_GUINT32_FORMAT,
72 		   g_variant_get_uint32(gVar));
73     } else if (g_variant_type_is_subtype_of(gVType, G_VARIANT_TYPE_UINT64)) {
74 	g_snprintf(result, MAKER_DIALOG_VALUE_LENGTH, "%" G_GUINT64_FORMAT,
75 		   g_variant_get_uint64(gVar));
76     } else if (g_variant_type_is_subtype_of(gVType, G_VARIANT_TYPE_INT16)) {
77 	g_snprintf(result, MAKER_DIALOG_VALUE_LENGTH, "%" G_GINT16_FORMAT,
78 		   g_variant_get_int16(gVar));
79     } else if (g_variant_type_is_subtype_of(gVType, G_VARIANT_TYPE_INT32)) {
80 	g_snprintf(result, MAKER_DIALOG_VALUE_LENGTH, "%" G_GINT32_FORMAT,
81 		   g_variant_get_int32(gVar));
82     } else if (g_variant_type_is_subtype_of(gVType, G_VARIANT_TYPE_INT64)) {
83 	g_snprintf(result, MAKER_DIALOG_VALUE_LENGTH, "%" G_GINT64_FORMAT,
84 		   g_variant_get_int64(gVar));
85     } else if (g_variant_type_is_subtype_of(gVType, G_VARIANT_TYPE_STRING)) {
86 	g_snprintf(result, MAKER_DIALOG_VALUE_LENGTH, "%s",
87 		   g_variant_get_string(gVar, NULL));
88     }
89     return result;
90 }
91 
92 /*============================================
93  * Class routines
94  */
95 
96 #define KEY_BUFFER_SIZE 300
97 
98 /*=== Start Schema Writing ===*/
mkdg_g_settings_write_schema_spec(FILE * file,MkdgPropertySpec * spec)99 gboolean mkdg_g_settings_write_schema_spec(FILE * file,
100 					   MkdgPropertySpec * spec)
101 {
102     if (spec->propertyFlags & MKDG_PROPERTY_FLAG_NO_BACKEND){
103 	return TRUE;
104     }
105     gchar attrBuf[KEY_BUFFER_SIZE];
106     const gchar *typeString = mkdg_g_variant_type_string(spec->valueType);
107     g_strlcpy(attrBuf, "", KEY_BUFFER_SIZE);
108     mkdg_xml_attr_append(attrBuf, KEY_BUFFER_SIZE, "name", spec->key);
109     mkdg_xml_attr_append(attrBuf, KEY_BUFFER_SIZE, "type", typeString);
110     mkdg_xml_tags_write(file, "key",
111 			MKDG_XML_TAG_TYPE_BEGIN_ONLY, attrBuf, NULL);
112     /* tag default */
113     g_strlcpy(attrBuf, "", KEY_BUFFER_SIZE);
114     if (spec->propertyFlags & MKDG_PROPERTY_FLAG_HAS_TRANSLATION) {
115 	mkdg_xml_attr_append(attrBuf, KEY_BUFFER_SIZE, "l10n", "messages");
116 	if (!STRING_IS_EMPTY(spec->translationContext)) {
117 	    mkdg_xml_attr_append(attrBuf, KEY_BUFFER_SIZE, "context",
118 				 spec->translationContext);
119 	}
120     }
121 
122     gchar *valueStr = NULL;
123     switch (spec->valueType) {
124     case G_TYPE_BOOLEAN:
125 	valueStr =
126 	    g_strdup_printf("%s",
127 			    (STRING_EQUALS(spec->defaultValue, "0")) ?
128 			    "false" : "true");
129 	break;
130     case G_TYPE_STRING:
131 	valueStr = g_strdup_printf("\"%s\"", spec->defaultValue);
132 	break;
133     default:
134 	valueStr = g_strdup_printf("%s", spec->defaultValue);
135 	break;
136     }
137     mkdg_xml_tags_write(file, "default",
138 			MKDG_XML_TAG_TYPE_SHORT, attrBuf, valueStr);
139     g_free(valueStr);
140     mkdg_xml_tags_write(file, "summary",
141 			MKDG_XML_TAG_TYPE_SHORT, NULL, spec->label);
142     mkdg_xml_tags_write(file, "description",
143 			MKDG_XML_TAG_TYPE_LONG, NULL, spec->tooltip);
144     mkdg_xml_tags_write(file, "key",
145 			MKDG_XML_TAG_TYPE_END_ONLY, NULL, NULL);
146     return TRUE;
147 }
148 
mkdg_g_settings_write_schema_from_spec_array(const gchar * schemaId,const gchar * basePath,FILE * file,MkdgPropertySpec specs[],const gchar * gettextDomain)149 gboolean mkdg_g_settings_write_schema_from_spec_array(const gchar *
150 						      schemaId,
151 						      const gchar *
152 						      basePath,
153 						      FILE * file,
154 						      MkdgPropertySpec
155 						      specs[],
156 						      const gchar *
157 						      gettextDomain)
158 {
159     mkdg_log(DEBUG,
160 	     "mkdg_g_settings_write_schema_from_spec_array(%s,%s,-,-,-,%s)",
161 	     schemaId, basePath, gettextDomain);
162     gchar attrBuf[KEY_BUFFER_SIZE];
163     gchar path[KEY_BUFFER_SIZE];
164     g_snprintf(path, KEY_BUFFER_SIZE, "%s", basePath);
165 
166     /* Header */
167     mkdg_xml_tags_write(file, "schemalist",
168 			MKDG_XML_TAG_TYPE_BEGIN_ONLY, NULL, NULL);
169     g_strlcpy(attrBuf, "", KEY_BUFFER_SIZE);
170     mkdg_xml_attr_append(attrBuf, KEY_BUFFER_SIZE, "id", schemaId);
171     mkdg_xml_attr_append(attrBuf, KEY_BUFFER_SIZE, "path", path);
172     mkdg_xml_attr_append(attrBuf, KEY_BUFFER_SIZE,
173 			 "gettext-domain", gettextDomain);
174     mkdg_xml_tags_write(file, "schema",
175 			MKDG_XML_TAG_TYPE_BEGIN_ONLY, attrBuf, NULL);
176     /* Body */
177     gint i;
178     for (i = 0; (&specs[i])->valueType != G_TYPE_INVALID; i++) {
179 	mkdg_g_settings_write_schema_spec(file, &specs[i]);
180     }
181 
182     /* Footer */
183     mkdg_xml_tags_write(file, "schema",
184 			MKDG_XML_TAG_TYPE_END_ONLY, NULL, NULL);
185     mkdg_xml_tags_write(file, "schemalist",
186 			MKDG_XML_TAG_TYPE_END_ONLY, NULL, NULL);
187     return TRUE;
188 }
189 
190 /*=== End Schema Writing ===*/
191 
mkdg_g_settings_read_value(GSettings * settings,GValue * value,const gchar * key)192 GValue *mkdg_g_settings_read_value(GSettings * settings,
193 				   GValue * value, const gchar * key)
194 {
195     GVariant *confValue = g_settings_get_value(settings, key);
196     mkdg_log(DEBUG, "mkdg_g_settings_read_value(-,-,%s)", key);
197     if (confValue == NULL) {
198 	mkdg_log(ERROR, "mkdg_g_settings_read_value(-,-,%s)", key);
199 	return NULL;
200     }
201     mkdg_g_variant_to_g_value(confValue, value);
202     return value;
203 }
204 
205 
206 /*============================================
207  * Interface routines
208  */
mkdg_g_settings_backend_get_key(MkdgBackend * backend,const gchar * section,const gchar * key,gpointer userData)209 gchar *mkdg_g_settings_backend_get_key(MkdgBackend * backend,
210 				       const gchar * section,
211 				       const gchar * key,
212 				       gpointer userData)
213 {
214     return (gchar *) key;
215 }
216 
mkdg_g_settings_backend_read_value(MkdgBackend * backend,GValue * value,const gchar * section,const gchar * key,gpointer userData)217 GValue *mkdg_g_settings_backend_read_value(MkdgBackend * backend,
218 					   GValue * value,
219 					   const gchar * section,
220 					   const gchar * key,
221 					   gpointer userData)
222 {
223     GSettings *config = (GSettings *) backend->config;
224     return mkdg_g_settings_read_value(config, value, key);
225 }
226 
227 
mkdg_g_settings_backend_write_value(MkdgBackend * backend,GValue * value,const gchar * section,const gchar * key,gpointer userData)228 gboolean mkdg_g_settings_backend_write_value(MkdgBackend *
229 					     backend,
230 					     GValue *
231 					     value,
232 					     const gchar *
233 					     section,
234 					     const gchar *
235 					     key, gpointer userData)
236 {
237     GSettings *config = (GSettings *) backend->config;
238     GVariant *confValue =
239 	g_variant_ref_sink(mkdg_g_value_to_g_variant(value));
240     mkdg_log(DEBUG, "mkdg_g_settings_write_value(-,%s,%s) %s",
241 	     mkdg_g_value_to_string(value), key,
242 	     mkdg_g_variant_to_string(confValue));
243     gboolean result = g_settings_set_value(config, key, confValue);
244     g_settings_sync();
245     if (!result) {
246 	mkdg_log(ERROR,
247 		 "mkdg_g_settings_backend_write_value(-,%s,%s,%s,-): Fail g_settings_set_value",
248 		 mkdg_g_value_to_string(value), section, key);
249     }
250     g_variant_unref(confValue);
251     return result;
252 }
253 
mkdg_g_settings_backend_new(const gchar * schemaId,const gchar * basePath,gpointer auxData)254 MkdgBackend *mkdg_g_settings_backend_new(const gchar *
255 					 schemaId,
256 					 const gchar *
257 					 basePath, gpointer auxData)
258 {
259     GSettings *client = g_settings_new(schemaId);
260     MkdgBackend *result =
261 	mkdg_backend_new(GSETTINGS_BACKEND_ID, (gpointer) client, basePath,
262 			 auxData);
263 
264     result->getKeyFunc = mkdg_g_settings_backend_get_key;
265     result->readFunc = mkdg_g_settings_backend_read_value;
266     result->writeFunc = mkdg_g_settings_backend_write_value;
267     return result;
268 }
269