summaryrefslogtreecommitdiff
path: root/libcaribou/json-deserializer.vala
blob: ea448a47d7565fadda4c10ad791ef14c89ae6f05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
namespace Caribou {

    private class JsonDeserializer : Object {

        public static bool get_layout_file_inner (string data_dir,
                                                  string group,
                                                  string variant,
                                                  out File fp) {
            string[] files = {@"$(group)_$(variant).json", @"$(group).json"};

            foreach (string fn in files) {
                string layout_fn = GLib.Path.build_filename (data_dir, fn);
                fp = GLib.File.new_for_path (layout_fn);
                if (fp.query_exists ())
                    return true;
            }

            return false;
        }

        public static GLib.File get_layout_file (string keyboard_type, string group,
                                                 string variant) throws IOError {

            List<string> dirs = new List<string> ();
            string custom_dir = Environment.get_variable("CARIBOU_LAYOUTS_DIR");

            if (custom_dir != null)
                dirs.append (Path.build_filename (custom_dir, "layouts",
                                                  keyboard_type));

            dirs.append (Path.build_filename (Environment.get_user_data_dir (),
                                              "caribou", "layouts", keyboard_type));

            foreach (string data_dir in Environment.get_system_data_dirs ()) {
                dirs.append (Path.build_filename (
                                 data_dir, "caribou", "layouts", keyboard_type));
            }

            foreach (string data_dir in dirs) {
                File fp;
                if (get_layout_file_inner (data_dir, group, variant, out fp))
                    return fp;
            }

            throw new IOError.NOT_FOUND (
                "Could not find layout file for %s %s", group, variant);                       }

        public static GroupModel? load_group (string keyboard_type,
                                              string group, string variant) {
            Json.Parser parser = new Json.Parser ();

            try {
                GLib.File f = get_layout_file (keyboard_type, group, variant);
                parser.load_from_stream (f.read (), (Cancellable) null);
            } catch (GLib.Error e) {
                stdout.printf ("Failed to load JSON: %s\n", e.message);
                return null;
            }

            GroupModel grp = new GroupModel (group, variant);
            create_levels_from_json (grp, parser.get_root ());

            return grp;
        }

        public static void create_levels_from_json (GroupModel group,
                                                    Json.Node root) {
            Json.Object obj = root.get_object ();

            if (root.get_node_type () != Json.NodeType.OBJECT)
                return;

            foreach (string levelname in obj.get_members ()) {
                unowned Json.Object json_level = obj.get_object_member (levelname);
                string mode = "";

                if (json_level.has_member ("mode"))
                    mode = json_level.get_string_member ("mode");

                Json.Array json_rows = json_level.get_array_member ("rows");
                LevelModel level = new LevelModel(mode);
                load_rows (level, json_rows);

                group.add_level(levelname, level);
            }
        }

        public static void load_rows (LevelModel level, Json.Array json_rows) {
            for (int i=0;i<json_rows.get_length ();i++) {
                Json.Array json_children = json_rows.get_array_element (i);
                unowned Json.Node child = json_children.get_element(0);
                if (child.get_node_type () == Json.NodeType.OBJECT) {
                    for (int j=0;j<json_children.get_length ();j++) {
                        Json.Object json_key = json_children.get_object_element (j);
                        level.add_key (i, 0, load_key (json_key));
                    }
                } else if (child.get_node_type () == Json.NodeType.ARRAY) {
                    for (int k=0;k<json_children.get_length ();k++) {
                        Json.Array json_keys = json_children.get_array_element (k);
                        for (int j=0;j<json_keys.get_length ();j++) {
                            Json.Object json_key = json_keys.get_object_element (j);
                            level.add_key (i, k, load_key (json_key));
                        }
                    }
                }
            }
        }

        public static KeyModel load_key (Json.Object json_key) {
            KeyModel key = new KeyModel (json_key.get_string_member ("name"));

            if (json_key.has_member ("toggle"))
                key.toggle = json_key.get_string_member ("toggle");

            if (json_key.has_member ("margin_left"))
                key.margin_left = json_key.get_double_member ("margin_left");

            if (json_key.has_member ("width"))
                key.width = json_key.get_double_member ("width");

            if (json_key.has_member ("extended_names")) {
                Json.Array json_keys = json_key.get_array_member ("extended_names");
                uint nkeys = json_keys.get_length ();
                uint i;

                key.add_subkey(key.name);

                for (i=0;i<nkeys;i++)
                    key.add_subkey(json_keys.get_string_element (i));
            }

            return key;
        }
        
    }
}