Skip to content

Commit 527f5e9

Browse files
committed
Use FileFormat items to load data
1 parent ed185e9 commit 527f5e9

File tree

15 files changed

+720
-176
lines changed

15 files changed

+720
-176
lines changed

src/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ vala_precompile(VALA_C
2727

2828
Services/FileFormat/SpiceUpFile.vala
2929
Services/FileFormat/ZipArchiveHandler.vala
30+
Services/FileFormat/JsonObject.vala
31+
32+
Services/FileFormat/Objects/CanvasItem.vala
33+
Services/FileFormat/Objects/Presentation.vala
34+
Services/FileFormat/Objects/Slide.vala
3035

3136
Widgets/Canvas.vala
3237
Widgets/EntryCombo.vala
Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
/*
2+
* Copyright (C) 2019 Felipe Escoto <[email protected]>
3+
*
4+
* This program or library is free software; you can redistribute it
5+
* and/or modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 3 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General
15+
* Public License along with this library; if not, write to the
16+
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17+
* Boston, MA 02110-1301 USA.
18+
*/
19+
20+
public abstract class Spice.FileFormat.JsonObject : GLib.Object {
21+
22+
[Signal (no_recurse = true, run = "first", action = true, no_hooks = true, detailed = true)]
23+
public signal void changed (string changed_property);
24+
25+
public Json.Object object { get; construct; }
26+
public JsonObject? parent_object { get; construct; default = null; }
27+
28+
private ObjectClass obj_class;
29+
30+
public JsonObject.from_object (Json.Object object) {
31+
Object (object: object);
32+
}
33+
34+
construct {
35+
obj_class = (ObjectClass) get_type ().class_ref ();
36+
37+
var properties = obj_class.list_properties ();
38+
foreach (var prop in properties) {
39+
load_key (prop.name, object);
40+
}
41+
}
42+
43+
public void connect_signals () {
44+
notify.connect (handle_notify);
45+
}
46+
47+
private void handle_notify (Object sender, ParamSpec property) {
48+
notify.disconnect (handle_notify);
49+
50+
save_on_object (property.name);
51+
call_verify (property.name);
52+
53+
notify.connect (handle_notify);
54+
}
55+
56+
private void call_verify (string key) {
57+
if (key == "object" || key == "parent-object") {
58+
return;
59+
}
60+
61+
if (internal_changed (key)) {
62+
changed (key);
63+
}
64+
}
65+
66+
/**
67+
* For reacting to internal changes.
68+
*
69+
* Return false to prevent the triggering of the changed signal
70+
*/
71+
protected virtual bool internal_changed (string key) {
72+
return true;
73+
}
74+
75+
/**
76+
* Used when a JSON Property has a different name than a GObject property.
77+
* This should return the name of the JSON property that you want to get from a gobject string.
78+
*
79+
* For example. GObject properties internally use "-" instead of "_"
80+
*/
81+
protected virtual string key_override (string key) {
82+
return key;
83+
}
84+
85+
private void load_key (string key, Json.Object source_object) {
86+
if (key == "object" || key == "parent-object") {
87+
return;
88+
}
89+
90+
string get_key = key_override (key);
91+
92+
if (!source_object.has_member (get_key)) {
93+
return;
94+
}
95+
96+
var prop = obj_class.find_property (key);
97+
98+
var type = prop.value_type;
99+
var val = Value (type);
100+
101+
if (val.type () == prop.value_type) {
102+
if (type == typeof (int))
103+
set_property (prop.name, (int) source_object.get_int_member (get_key));
104+
else if (type == typeof (uint))
105+
set_property (prop.name, (uint) source_object.get_int_member (get_key));
106+
else if (type == typeof (double))
107+
set_property (prop.name, source_object.get_double_member (get_key));
108+
else if (type == typeof (string))
109+
set_property (prop.name, source_object.get_string_member (get_key));
110+
else if (type == typeof (bool))
111+
set_property (prop.name, source_object.get_boolean_member (get_key));
112+
else if (type == typeof (int64))
113+
set_property (prop.name, source_object.get_int_member (get_key));
114+
else if (type.is_a (typeof (JsonObject))) {
115+
var object = source_object.get_object_member (get_key);
116+
if (val.get_object () == null) {
117+
set_property (prop.name, Object.new (type, "object", source_object, "parent-object", this));
118+
} else {
119+
var json_object = (JsonObject) val.get_object ();
120+
json_object.override_properties_from_json (object);
121+
}
122+
} else if (type.is_a (typeof (Spice.FileFormat.JsonObjectArray))) {
123+
if (val.get_object () == null) {
124+
set_property (prop.name, Object.new (type, "object", source_object, "property_name", prop.name));
125+
} else {
126+
// Set elements to existing array
127+
}
128+
} else if (type == typeof (string[])) {
129+
var list = new Gee.LinkedList<string> ();
130+
source_object.get_array_member (get_key).get_elements ().foreach ((node) => {
131+
list.add (node.get_string ());
132+
});
133+
set_property (prop.name, list.to_array ());
134+
} else {
135+
print ("type error%s\n", type.name ());
136+
}
137+
} else {
138+
print ("Unsupported settings type '%s' in object\n", type.name ());
139+
}
140+
}
141+
142+
protected string get_string_property (string key) {
143+
var prop = obj_class.find_property (key);
144+
145+
var type = prop.value_type;
146+
var val = Value (type);
147+
this.get_property (prop.name.down (), ref val);
148+
149+
if (val.type () == prop.value_type) {
150+
if (type == typeof (int))
151+
return ((int) val).to_string ();
152+
else if (type == typeof (uint))
153+
return ((uint) val).to_string ();
154+
else if (type == typeof (double))
155+
return ((double) val).to_string ();
156+
else if (type == typeof (string))
157+
return ((string) val).to_string ();
158+
else if (type == typeof (bool))
159+
return ((bool) val).to_string ();
160+
else if (type == typeof (int64))
161+
return ((int64) val).to_string ();
162+
}
163+
164+
assert_not_reached ();
165+
}
166+
167+
/*
168+
* Runs when you set a vala property on the object to store the value in the internal JSON class
169+
*/
170+
private void save_on_object (string key) {
171+
if (key == "object" || key == "parent-object") {
172+
return;
173+
}
174+
175+
string get_key = key_override (key);
176+
177+
var prop = obj_class.find_property (key);
178+
179+
// Do not attempt to save a non-mapped key
180+
if (prop == null)
181+
return;
182+
183+
var type = prop.value_type;
184+
var val = Value (type);
185+
this.get_property (prop.name, ref val);
186+
187+
if (val.type () == prop.value_type) {
188+
if (type == typeof (int)) {
189+
if (val.get_int () != object.get_int_member (key)) {
190+
object.set_int_member (get_key, val.get_int ());
191+
}
192+
} else if (type == typeof (uint)) {
193+
if (val.get_uint () != object.get_int_member (key)) {
194+
object.set_int_member (get_key, val.get_uint ());
195+
}
196+
} else if (type == typeof (int64)) {
197+
if (val.get_int64 () != object.get_int_member (key)) {
198+
object.set_int_member (get_key, val.get_int64 ());
199+
}
200+
} else if (type == typeof (double)) {
201+
if (val.get_double () != object.get_double_member (key)) {
202+
object.set_double_member (key, val.get_double ());
203+
}
204+
} else if (type == typeof (string)) {
205+
if (val.get_string () != object.get_string_member (key)) {
206+
object.set_string_member (key, val.get_string ());
207+
}
208+
} else if (type == typeof (string[])) {
209+
// string[] strings = null;
210+
// this.get (key, &strings);
211+
// if (strings != schema.get_strv (key)) {
212+
// schema.set_strv (key, strings);
213+
// }
214+
} else if (type == typeof (bool)) {
215+
if (val.get_boolean () != object.get_boolean_member (key)) {
216+
object.set_boolean_member (key, val.get_boolean ());
217+
}
218+
}
219+
}
220+
}
221+
222+
/**
223+
* Get's a string representation of this object. Useful for serialization
224+
*/
225+
public string to_string (bool prettyfied) {
226+
var node = new Json.Node.alloc ();
227+
node.set_object (object);
228+
229+
return Json.to_string (node, prettyfied);
230+
}
231+
232+
/**
233+
* Got a new Json Object and want to update it's properties. Do it from here!
234+
*/
235+
public void override_properties_from_json (Json.Object new_object) {
236+
notify.disconnect (handle_notify);
237+
238+
var properties = obj_class.list_properties ();
239+
foreach (var prop in properties) {
240+
var prop_name = prop.name;
241+
if (prop_name == "object" || prop_name == "parent-object") {
242+
continue;
243+
}
244+
245+
string get_key = key_override (prop_name);
246+
if (!new_object.has_member (get_key)) {
247+
return;
248+
}
249+
250+
var type = prop.value_type;
251+
var original_value = Value (type);
252+
253+
if (ParamFlags.READABLE in prop.flags) {
254+
this.get_property (prop_name.down (), ref original_value);
255+
}
256+
257+
bool change_prop = false;
258+
259+
if (type == typeof (int)) {
260+
change_prop = (original_value.get_int () != new_object.get_int_member (get_key));
261+
} else if (type == typeof (uint)) {
262+
change_prop = (original_value.get_uint () != new_object.get_int_member (get_key));
263+
} else if (type == typeof (int64)) {
264+
change_prop = (original_value.get_int64 () != new_object.get_int_member (get_key));
265+
} else if (type == typeof (double)) {
266+
change_prop = (original_value.get_double () != new_object.get_double_member (get_key));
267+
} else if (type == typeof (string)) {
268+
change_prop = (original_value.get_string () != new_object.get_string_member (get_key));
269+
} else if (type == typeof (string[])) {
270+
// string[] strings = null;
271+
// this.get (key, &strings);
272+
// if (strings != schema.get_strv (key)) {
273+
// schema.set_strv (key, strings);
274+
// }
275+
} else if (type == typeof (bool)) {
276+
change_prop = (original_value.get_boolean () != new_object.get_boolean_member (get_key));
277+
} else if (type.is_a (typeof (JsonObject))) {
278+
var object = new_object.get_object_member (get_key);
279+
280+
var json_object = (JsonObject) original_value.get_object ();
281+
json_object.override_properties_from_json (object);
282+
}
283+
284+
if (change_prop) {
285+
load_key (prop.name, new_object);
286+
changed (prop.name);
287+
}
288+
}
289+
290+
notify.connect (handle_notify);
291+
}
292+
}
293+
294+
public abstract class Spice.FileFormat.JsonObjectArray : Object {
295+
public unowned Json.Object object { get; construct; }
296+
public string property_name { get; construct; }
297+
298+
public JsonObjectArray (Json.Object object, string property_name) {
299+
Object (object: object, property_name: property_name);
300+
}
301+
302+
construct {
303+
load_array ();
304+
}
305+
306+
/**
307+
* Can be overriten to add more than one type of item into the array
308+
*/
309+
protected virtual void load_array () {
310+
object.get_array_member (property_name).get_elements ().foreach ((node) => {
311+
add_to_list ((FileFormat.JsonObject) Object.new (get_type_of_array (),
312+
"object", node.get_object (),
313+
"parent-object", null));
314+
});
315+
}
316+
317+
public abstract void add_to_list (FileFormat.JsonObject json_object);
318+
public abstract Type get_type_of_array ();
319+
}

0 commit comments

Comments
 (0)