Merge lp:~teemperor/switchboard-plug-keyboard/fix-layouts into lp:~elementary-pantheon/switchboard-plug-keyboard/trunk

Proposed by Raphael Isemann
Status: Merged
Approved by: Corentin Noël
Approved revision: 207
Merged at revision: 206
Proposed branch: lp:~teemperor/switchboard-plug-keyboard/fix-layouts
Merge into: lp:~elementary-pantheon/switchboard-plug-keyboard/trunk
Diff against target: 1315 lines (+635/-485)
6 files modified
src/Pages/Layout/add_layout.vala (+2/-2)
src/Pages/Layout/display.vala (+205/-224)
src/Pages/Layout/handler.vala (+33/-34)
src/Pages/Layout/settings.vala (+370/-154)
src/Pages/layout.vala (+15/-51)
src/keyboard.vala (+10/-20)
To merge this branch: bzr merge lp:~teemperor/switchboard-plug-keyboard/fix-layouts
Reviewer Review Type Date Requested Status
ilian (community) Approve
Corentin Noël Approve
Review via email: mp+230324@code.launchpad.net

Commit message

Fix the layout panel

Description of the change

Ok, we merge that or we get just flooded with bug-reports as the plug currently doesn't work at all.

To post a comment you must log in.
Revision history for this message
Corentin Noël (tintou) wrote :

Even if it doesn't respect ANY elementary codestyle rule, I approve the bug fix

review: Approve
Revision history for this message
ilian (9-ilian) wrote :

I`ve tryed to disable or fully remove Ibus, changing stuff in 'desktop.ibus.general and hotkeys.
Also edited "org.gnome.desktop.input-sources.sources and xkb-options" - no effect
Same with "org.gnome.libgnomekbd.keyboard" my layouts are "['us', 'bg+phonetic']" and options to "['grp\tgrp:alt_shift_toggle']" still shortcut don't working.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/Pages/Layout/add_layout.vala'
--- src/Pages/Layout/add_layout.vala 2014-01-06 17:12:27 +0000
+++ src/Pages/Layout/add_layout.vala 2014-08-11 14:54:46 +0000
@@ -1,7 +1,7 @@
1namespace Pantheon.Keyboard.Layout1namespace Pantheon.Keyboard.LayoutPage
2{2{
3 // pop over widget to add a new keyboard layout3 // pop over widget to add a new keyboard layout
4 class AddLayout : Gtk.Dialog//Granite.Widgets.PopOver4 class AddLayout : Gtk.Dialog
5 {5 {
6 public signal void layout_added (int language, int layout = 0);6 public signal void layout_added (int language, int layout = 0);
77
88
=== modified file 'src/Pages/Layout/display.vala'
--- src/Pages/Layout/display.vala 2014-01-06 17:12:27 +0000
+++ src/Pages/Layout/display.vala 2014-08-11 14:54:46 +0000
@@ -1,226 +1,207 @@
1namespace Pantheon.Keyboard.Layout1namespace Pantheon.Keyboard.LayoutPage
2{2{
3 // widget to display/add/remove/move keyboard layouts3 // widget to display/add/remove/move keyboard layouts
4 // interacts with class SettingsLayout4 class Display : Gtk.Grid
5 class Display : Gtk.Grid5 {
6 {6
7 private signal void update_buttons ();7 LayoutSettings settings;
88 Gtk.TreeView tree;
9 private SettingsLayouts settings;9 Gtk.ToolButton up_button;
10 private Gtk.TreeView tree;10 Gtk.ToolButton down_button;
1111 Gtk.ToolButton add_button;
12 public Display ()12 Gtk.ToolButton remove_button;
13 {13
14 settings = new SettingsLayouts ();14 /*
15 var list = make_list_store ();15 * Set to true when the user has just clicked on the list to prevent
16 tree = new Gtk.TreeView.with_model (list);16 * that settings.layouts.active_changed triggers update_cursor
17 var cell = new Gtk.CellRendererText ();17 */
1818 bool cursor_changing = false;
19 tree.insert_column_with_attributes (-1, null, cell, "text", 0);19
20 tree.headers_visible = false;20 public Display ()
21 tree.expand = true;21 {
2222 settings = LayoutSettings.get_instance ();
23 var scroll = new Gtk.ScrolledWindow(null, null);23
24 scroll.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC;24 tree = new Gtk.TreeView ();
25 scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;25 var cell = new Gtk.CellRendererText ();
26 scroll.shadow_type = Gtk.ShadowType.IN;26
27 scroll.add(tree);27 tree.insert_column_with_attributes (-1, null, cell, "text", 0);
28 scroll.expand = true;28 tree.headers_visible = false;
2929 tree.expand = true;
30 var tbar = new Gtk.Toolbar();30 rebuild_list ();
31 tbar.set_style(Gtk.ToolbarStyle.ICONS);31
32 tbar.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR);32 var scroll = new Gtk.ScrolledWindow(null, null);
33 tbar.set_show_arrow(false);33 scroll.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
34 tbar.hexpand = true;34 scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
3535 scroll.shadow_type = Gtk.ShadowType.IN;
36 scroll.get_style_context().set_junction_sides(Gtk.JunctionSides.BOTTOM);36 scroll.add (tree);
37 tbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR);37 scroll.expand = true;
38 tbar.get_style_context().set_junction_sides(Gtk.JunctionSides.TOP);38
3939 var tbar = new Gtk.Toolbar();
40 var add_button = new Gtk.ToolButton (null, _("Add…"));40 tbar.set_style(Gtk.ToolbarStyle.ICONS);
41 var remove_button = new Gtk.ToolButton (null, _("Remove"));41 tbar.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR);
42 var up_button = new Gtk.ToolButton (null, _("Move up"));42 tbar.set_show_arrow(false);
43 var down_button = new Gtk.ToolButton (null, _("Move down"));43 tbar.hexpand = true;
4444
45 add_button.set_tooltip_text (_("Add…"));45 scroll.get_style_context().set_junction_sides(Gtk.JunctionSides.BOTTOM);
46 remove_button.set_tooltip_text (_("Remove"));46 tbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR);
47 up_button.set_tooltip_text (_("Move up"));47 tbar.get_style_context().set_junction_sides(Gtk.JunctionSides.TOP);
48 down_button.set_tooltip_text (_("Move down"));48
4949 add_button = new Gtk.ToolButton (null, _("Add…"));
50 add_button.set_icon_name ("list-add-symbolic");50 remove_button = new Gtk.ToolButton (null, _("Remove"));
51 remove_button.set_icon_name ("list-remove-symbolic");51 up_button = new Gtk.ToolButton (null, _("Move up"));
52 up_button.set_icon_name ("go-up-symbolic");52 down_button = new Gtk.ToolButton (null, _("Move down"));
53 down_button.set_icon_name ("go-down-symbolic");53
5454 add_button.set_tooltip_text (_("Add…"));
55 remove_button.sensitive = false;55 remove_button.set_tooltip_text (_("Remove"));
56 up_button.sensitive = false;56 up_button.set_tooltip_text (_("Move up"));
57 down_button.sensitive = false;57 down_button.set_tooltip_text (_("Move down"));
5858
59 tbar.insert (add_button, -1);59 add_button.set_icon_name ("list-add-symbolic");
60 tbar.insert (remove_button, -1);60 remove_button.set_icon_name ("list-remove-symbolic");
61 tbar.insert (up_button, -1);61 up_button.set_icon_name ("go-up-symbolic");
62 tbar.insert (down_button, -1);62 down_button.set_icon_name ("go-down-symbolic");
6363
64 this.attach (scroll, 0, 0, 1, 1);64 remove_button.sensitive = false;
65 this.attach (tbar, 0, 1, 1, 1);65 up_button.sensitive = false;
6666 down_button.sensitive = false;
67 var pop = new AddLayout ();67
6868 tbar.insert (add_button, -1);
69 add_button.clicked.connect( () => {69 tbar.insert (remove_button, -1);
70 // uncomment when reverting to popover70 tbar.insert (up_button, -1);
71 //pop.move_to_widget (add_button);71 tbar.insert (down_button, -1);
72 // and remove this line72
73 pop.show_all ();73 this.attach (scroll, 0, 0, 1, 1);
74 add_item (tree, pop);74 this.attach (tbar, 0, 1, 1, 1);
75 } );75
7676 var pop = new AddLayout ();
77 remove_button.clicked.connect( () => {77
78 remove_item (tree);78 add_button.clicked.connect( () => {
79 update_buttons ();79 // uncomment when reverting to popover
80 } );80 //pop.move_to_widget (add_button);
8181 // and remove this line
82 up_button.clicked.connect (() => {82 pop.show_all ();
83 move_item (tree, 0);83 add_item (pop);
84 update_buttons ();84 });
85 } );85
8686 remove_button.clicked.connect( () => {
87 down_button.clicked.connect (() => {87 remove_item ();
88 move_item (tree, 1);88 });
89 update_buttons ();89
90 } );90 up_button.clicked.connect (() => {
9191 settings.layouts.move_active_layout_up ();
92 tree.cursor_changed.connect (() => {92 rebuild_list ();
93 update_buttons ();93 });
94 } );94
9595 down_button.clicked.connect (() => {
96 this.update_buttons.connect (() =>96 settings.layouts.move_active_layout_down ();
97 {97 rebuild_list ();
98 Gtk.TreePath path;98 });
9999
100 tree.get_cursor (out path, null);100 tree.cursor_changed.connect (() => {
101101 cursor_changing = true;
102 if (path == null)102 int new_index = get_cursor_index ();
103 {103 if (new_index != -1) {
104 up_button.sensitive = false;104 settings.layouts.active = new_index;
105 down_button.sensitive = false;105 }
106 remove_button.sensitive = false;106 update_buttons ();
107 return;107
108 }108 cursor_changing = false;
109109 });
110 int index = (path.get_indices ())[0];110
111 int count = settings.layouts.length - 1;111 settings.layouts.active_changed.connect (() => {
112112 if (cursor_changing)
113 up_button.sensitive = (index != 0);113 return;
114 down_button.sensitive = (index != count);114 update_cursor ();
115 remove_button.sensitive = (count > 0);115 });
116 } );116 update_cursor ();
117 }117 }
118118
119 private Gtk.ListStore make_list_store ()119 public void reset_all ()
120 {120 {
121 Gtk.ListStore list_store = new Gtk.ListStore (3, typeof (string), typeof(uint), typeof(uint));121 settings.reset_all ();
122 Gtk.TreeIter iter;122 rebuild_list ();
123123 }
124 uint layout = 0, variant = 0;124
125125 void update_buttons () {
126 foreach (string item in settings.layouts)126 int index = get_cursor_index ();
127 {127
128 handler.from_code (item, out layout, out variant);128 // if empty list
129 item = handler.get_name (layout, variant);129 if (index == -1)
130130 {
131 list_store.append (out iter);131 up_button.sensitive = false;
132 list_store.set (iter, 0, item);132 down_button.sensitive = false;
133 list_store.set (iter, 1, layout);133 remove_button.sensitive = false;
134 list_store.set (iter, 2, variant);134 } else {
135 }135 up_button.sensitive = (index != 0);
136136 down_button.sensitive = (index != settings.layouts.length - 1);
137 return list_store;137 remove_button.sensitive = (settings.layouts.length > 0);
138 }138 }
139139 }
140 public void reset_all ()140
141 {141 /**
142 settings.reset_all ();142 * Returns the index of the selected layout in the UI.
143 tree.model = make_list_store ();143 * In case the list contains no layouts, it returns -1.
144 update_buttons ();144 */
145 }145 int get_cursor_index () {
146146 Gtk.TreePath path;
147 void add_item (Gtk.TreeView tree, Layout.AddLayout pop)147
148 {148 tree.get_cursor (out path, null);
149 pop.layout_added.connect ((layout, variant) =>149
150 {150 if (path == null)
151 Gtk.TreeIter iter;151 {
152152 return -1;
153 var name = handler.get_name (layout, variant);153 }
154 var code = handler.get_code (layout, variant);154
155 var list = tree.model as Gtk.ListStore;155 return (path.get_indices ())[0];
156156 }
157 if (settings.add_layout (code))157
158 {158 void update_cursor () {
159 list.append (out iter);159 Gtk.TreePath path = new Gtk.TreePath.from_indices (settings.layouts.active);
160 list.set (iter, 0, name);160 tree.set_cursor (path, null, false);
161 list.set (iter, 1, layout);161 }
162 list.set (iter, 2, variant);162
163163 Gtk.ListStore build_store () {
164 tree.set_cursor (list.get_path(iter), null, false);164 Gtk.ListStore list_store = new Gtk.ListStore (3, typeof (string), typeof(uint), typeof(uint));
165 update_buttons ();165 Gtk.TreeIter iter;
166 }166
167 } );167 uint layout = 0, variant = 0;
168 }168
169169 for (uint i = 0; i < settings.layouts.length; i++) {
170 void remove_item (Gtk.TreeView tree)170 string item = settings.layouts.get_layout (i).name;
171 {171 handler.from_code (item, out layout, out variant);
172 Gtk.TreeModel model;172 item = handler.get_name (layout, variant);
173 Gtk.TreeIter iter;173
174174 list_store.append (out iter);
175 var select = tree.get_selection();175 list_store.set (iter, 0, item);
176 select.get_selected (out model, out iter);176 list_store.set (iter, 1, layout);
177177 list_store.set (iter, 2, variant);
178 GLib.Value layout, variant;178 }
179 model.get_value (iter, 1, out layout);179 return list_store;
180 model.get_value (iter, 2, out variant);180 }
181181
182 settings.remove_layout (handler.get_code ((uint)layout, (uint)variant));182 void rebuild_list () {
183 stdout.printf ("%s\n", handler.get_code ((uint)layout, (uint)variant));183 tree.model = build_store ();
184 (model as Gtk.ListStore).remove(iter);184 update_cursor ();
185 }185 update_buttons ();
186186 }
187 void move_item (Gtk.TreeView tree, int dir)187
188 {188 void remove_item ()
189 Gtk.TreeModel model;189 {
190 Gtk.TreeIter iter_current, iter_new;190 settings.layouts.remove_active_layout ();
191 Gtk.TreePath path_current;191 rebuild_list ();
192192 }
193 var select = tree.get_selection();193
194 select.get_selected (out model, out iter_current);194 void add_item (LayoutPage.AddLayout pop)
195 path_current = model.get_path (iter_current);195 {
196196 pop.layout_added.connect ((layout, variant) => {
197 iter_new = iter_current;197
198198 var name = handler.get_name (layout, variant);
199 var store = model as Gtk.ListStore;199 var code = handler.get_code (layout, variant);
200200
201 switch (dir)201 // TODO variant
202 {202 settings.layouts.add_layout (new Layout.XKB (code, ""));
203 case 1: if (model.iter_next (ref iter_new) == false)203 rebuild_list ();
204 return;204 });
205 break;205 }
206 case 0: if (model.iter_previous (ref iter_new) == false)206 }
207 return;
208 break;
209 }
210
211 store.swap (iter_current, iter_new);
212
213 tree.set_cursor (model.get_path (iter_current), null, false);
214
215 switch (dir)
216 {
217 case 1:
218 settings.layout_down ((path_current.get_indices()) [0]);
219 break;
220 case 0:
221 settings.layout_up ((path_current.get_indices()) [0]);
222 break;
223 }
224 }
225 }
226}207}
227\ No newline at end of file208\ No newline at end of file
228209
=== modified file 'src/Pages/Layout/handler.vala'
--- src/Pages/Layout/handler.vala 2014-01-06 17:12:27 +0000
+++ src/Pages/Layout/handler.vala 2014-08-11 14:54:46 +0000
@@ -1,85 +1,84 @@
1namespace Pantheon.Keyboard.Layout1namespace Pantheon.Keyboard.LayoutPage
2{2{
3 // class that parses the layout file, provides lists of languages and3 // class that parses the layout file, provides lists of languages and
4 // variants, and converts between layout names and their gsettings codes 4 // variants, and converts between layout names and their gsettings codes
5 class LayoutHandler : GLib.Object5 class LayoutHandler : GLib.Object
6 {6 {
7 Layout[] layouts;7 InternalLayout[] layouts;
8 8
9 private string[] names;9 private string[] names;
10 private string[] codes;10 private string[] codes;
11 11
12 public LayoutHandler ()12 public LayoutHandler ()
13 {13 {
14 foreach (var l in parse_layouts ())14 foreach (var l in parse_layouts ())
15 {15 {
16 var parts = l.split(":", 2);16 var parts = l.split(":", 2);
17 17
18 names += parts[0];18 names += parts[0];
19 codes += parts[1];19 codes += parts[1];
20 20
21 layouts += new Layout (parse_variants (l));21 layouts += new InternalLayout (parse_variants (l));
22 }22 }
23 }23 }
24 24
25 public string[] get_layouts () {25 public string[] get_layouts () {
26 return names;26 return names;
27 }27 }
28 28
29 public string[] get_variants (uint index) {29 public string[] get_variants (uint index) {
30 return layouts[index].names;30 return layouts[index].names;
31 }31 }
32 32
33 public string get_code (uint l, uint v)33 public string get_code (uint l, uint v)
34 {34 {
35 if (v != 0)35 if (v != 0)
36 return codes[l] + "\t" + layouts[l].codes[v];36 return codes[l] + "+" + layouts[l].codes[v];
37 return codes[l];37 return codes[l];
38 }38 }
39 39
40 public string get_name (uint l, uint v)40 public string get_name (uint l, uint v)
41 {41 {
42 if (v != 0)42 if (v != 0)
43 return layouts[l].names[v];43 return layouts[l].names[v];
44 return names[l];44 return names[l];
45 }45 }
46 46
47 public bool from_code (string code, out uint l, out uint v)47 public bool from_code (string code, out uint l, out uint v)
48 {48 {
49 var parts = code.split("\t", 2);49 var parts = code.split("+", 2);
50 50
51 l = v = 0;51 l = v = 0;
52 52
53 if (parts[0] == null) return false;53 if (parts[0] == null) return false;
54 54
55 while (codes[l] != parts[0])55 while (codes[l] != parts[0])
56 if (l++ > codes.length)56 if (l++ > codes.length)
57 return false;57 return false;
58 58
59 if (parts[1] == null) return true;59 if (parts[1] == null) return true;
60 60
61 while (layouts[l].codes[v] != parts[1])61 while (layouts[l].codes[v] != parts[1])
62 if (v++ > layouts[l].codes.length)62 if (v++ > layouts[l].codes.length)
63 return false;63 return false;
64 64
65 return true;65 return true;
66 }66 }
6767
68 // private class that contains the variants of one language68 // private class that contains the variants of one language
69 private class Layout : GLib.Object69 private class InternalLayout : GLib.Object {
70 {
71 public string[] names;70 public string[] names;
72 public string[] codes;71 public string[] codes;
7372
74 public Layout( string[] variants )73 public InternalLayout (string[] variants )
75 {74 {
76 names += _("Default");75 names += _("Default");
77 codes += "";76 codes += "";
78 77
79 foreach (var v in variants)78 foreach (var v in variants)
80 {79 {
81 var parts = v.split(":", 2);80 var parts = v.split(":", 2);
82 81
83 names += parts[0];82 names += parts[0];
84 codes += parts[1];83 codes += parts[1];
85 }84 }
@@ -90,7 +89,7 @@
90 private string[]? parse_layouts ()89 private string[]? parse_layouts ()
91 {90 {
92 string[] return_val = null;91 string[] return_val = null;
93 92
94 var file = File.new_for_path (Build.PKGDATADIR + "/layouts.txt");93 var file = File.new_for_path (Build.PKGDATADIR + "/layouts.txt");
9594
96 if (!file.query_exists ()) {95 if (!file.query_exists ()) {
@@ -100,23 +99,23 @@
10099
101 try {100 try {
102 var dis = new DataInputStream (file.read ());101 var dis = new DataInputStream (file.read ());
103 102
104 string line;103 string line;
105 104
106 while ((line = dis.read_line (null)) != null)105 while ((line = dis.read_line (null)) != null)
107 if( "#" in line )106 if( "#" in line )
108 return_val += line.replace ("#", "");107 return_val += line.replace ("#", "");
109 } catch (Error e) {108 } catch (Error e) {
110 error ("%s", e.message);109 error ("%s", e.message);
111 }110 }
112 111
113 return return_val;112 return return_val;
114 }113 }
115114
116 private string[]? parse_variants (string language)115 private string[]? parse_variants (string language)
117 {116 {
118 string[] return_val = null;117 string[] return_val = null;
119 118
120 var file = File.new_for_path (Build.PKGDATADIR + "/layouts.txt");119 var file = File.new_for_path (Build.PKGDATADIR + "/layouts.txt");
121120
122 if (!file.query_exists ()) {121 if (!file.query_exists ()) {
@@ -126,11 +125,11 @@
126125
127 try {126 try {
128 var dis = new DataInputStream (file.read ());127 var dis = new DataInputStream (file.read ());
129 128
130 string line;129 string line;
131 130
132 while ((line = dis.read_line (null)) != null) {131 while ((line = dis.read_line (null)) != null) {
133 if (line == "#"+language) {132 if (line == "#" + language) {
134 while ((line = dis.read_line (null)) != null) {133 while ((line = dis.read_line (null)) != null) {
135 if( "#" in line ) break;134 if( "#" in line ) break;
136 return_val += line;135 return_val += line;
137136
=== modified file 'src/Pages/Layout/settings.vala'
--- src/Pages/Layout/settings.vala 2014-01-06 17:12:27 +0000
+++ src/Pages/Layout/settings.vala 2014-08-11 14:54:46 +0000
@@ -1,156 +1,372 @@
1namespace Pantheon.Keyboard.Layout1namespace Pantheon.Keyboard.LayoutPage
2{2{
3 // class to interact with gsettings and add/remove keyboard layouts3
4 class SettingsLayouts : Granite.Services.Settings4 /**
5 {5 * Type of a keyboard-layout as described in the description of
6 public string[] layouts { get; set; }6 * "org.gnome.desktop.input-sources sources".
7 7 */
8 public void validate ()8 enum LayoutType { IBUS, XKB }
9 {9
10 string[] copy = {};10 /**
11 foreach (string str in layouts)11 * Immutable class that respresents a keyboard-layout according to
12 {12 * "org.gnome.desktop.input-sources sources".
13 //if (handler.valid_code(str))13 * This means that the enum parameter @layout_type equals the first string in the
14 copy += str;14 * tupel of strings, and the @name parameter equals the second string.
15 }15 */
16 layouts = copy;16 class Layout {
17 }17
18 18 public LayoutType layout_type { get; private set; }
19 public bool add_layout (string layout)19 public string name { get; private set; }
20 {20
21 foreach (string str in layouts)21 public Layout (LayoutType layout_type, string name) {
22 {22 this.layout_type = layout_type;
23 if (str == layout)23 this.name = name;
24 return false;24 }
25 }25
26 string[] val = layouts;26 public Layout.XKB (string layout, string? variant) {
27 val += layout;27 string full_name = layout;
28 layouts = val;28 if (variant != null && variant != "")
29 return true;29 full_name += "+" + variant;
30 }30 this (LayoutType.XKB, full_name);
31 31 }
32 public void remove_layout (string layout)32
33 {33 public Layout.from_variant (GLib.Variant variant) {
34 string[] val = {};34 if (variant.is_of_type (new VariantType ("(ss)"))) {
35 35 unowned string type;
36 foreach (string str in layouts)36 unowned string name;
37 {37
38 if (str != layout)38 variant.get ("(&s&s)", out type, out name);
39 val += str;39
40 }40 if (type == "xkb") {
41 layouts = val;41 layout_type = LayoutType.XKB;
42 }42 } else if (type == "ibus") {
43 43 layout_type = LayoutType.IBUS;
44 public void layout_up (int i)44 } else {
45 {45 warning ("Unkown type %s", type);
46 var l = layouts;46 }
47 var tmp = l[i];47 this.name = name;
48 l[i] = l[i-1];48
49 l[i-1] = tmp;49 } else {
50 layouts = l;50 warning ("Variant has invalid type");
51 }51 }
52 52 }
53 public void layout_down (int i)53
54 {54 public bool equal (Layout other) {
55 var l = layouts;55 return this.layout_type == other.layout_type && this.name == other.name;
56 var tmp = l[i];56 }
57 l[i] = l[i+1];57
58 l[i+1] = tmp;58 /**
59 layouts = l;59 * GSettings saves values in the form of GLib.Variant and this
60 }60 * function creates a Variant representing this object.
61 61 */
62 public string[]? parse_default ()62 public GLib.Variant to_variant () {
63 {63 string type_name = "";
64 string[] return_val = null;64 switch (layout_type) {
65 65 case LayoutType.IBUS:
66 var file = File.new_for_path ("/etc/default/keyboard");66 type_name = "ibus";
6767 break;
68 if (!file.query_exists ())68 case LayoutType.XKB:
69 {69 type_name = "xkb";
70 warning ("File '%s' doesn't exist.\n", file.get_path ());70 break;
71 return null;71 default:
72 }72 error ("You need to implemnt this for all possible values of"
7373 + "the LayoutType-enum");
74 string xkb_layout = "";74 }
75 string xkb_variant = "";75 GLib.Variant first = new GLib.Variant.string (type_name);
7676 GLib.Variant second = new GLib.Variant.string (name);
77 try77 GLib.Variant result = new GLib.Variant.tuple ({first, second});
78 {78
79 var dis = new DataInputStream (file.read ());79 return result;
80 80 }
81 string line;81
82 82 }
83 while ((line = dis.read_line (null)) != null)83
84 {84 /**
85 if (line.contains ("XKBLAYOUT="))85 * Represents a list of layouts.
86 {86 */
87 xkb_layout = line.replace ("XKBLAYOUT=", "").replace ("\"", "");87 class LayoutList : Object {
88 88
89 while ((line = dis.read_line (null)) != null) {89 GLib.List<Layout> layouts = new GLib.List<Layout> ();
90 if (line.contains ("XKBVARIANT=")) {90
91 xkb_variant = line.replace ("XKBVARIANT=", "").replace ("\"", "");91 // signals
92 }92 public signal void layouts_changed ();
93 }93 public signal void active_changed ();
94 94
95 break;95 public uint length {
96 }96 get {
97 }97 return layouts.length ();
98 }98 }
9999 }
100 catch (Error e)100
101 {101 uint _active;
102 error ("%s", e.message);102 public uint active {
103 }103 get {
104 104 return _active;
105 var variants = xkb_variant.split (",");105 }
106 var layouts = xkb_layout.split (",");106 set {
107 107 if (length == 0)
108 for (int i = 0; i < layouts.length; i++)108 return;
109 {109
110 if (variants[i] != null && variants[i] != "")110 if (_active == value)
111 return_val += layouts[i] + "\t" + variants[i];111 return;
112 else112
113 return_val += layouts[i];113 _active = value;
114 }114 if (_active >= length)
115 115 _active = length - 1;
116 return return_val;116 active_changed ();
117 }117 }
118 118
119 public void reset_all ()119 }
120 {120
121 layouts = parse_default ();121 public bool contains_layout (Layout given_layout) {
122 validate ();122 return get_layout_index (given_layout) != -1;
123 reverted ();123 }
124 }124
125 125 public int get_layout_index (Layout given_layout) {
126 public signal void reverted ();126 int i = 0;
127 127 foreach (Layout l in layouts) {
128 public SettingsLayouts()128 if (l.equal (given_layout))
129 {129 return i;
130 base ("org.gnome.libgnomekbd.keyboard");130 i++;
131 131 }
132 if (layouts == null || layouts.length == 0)132 return -1;
133 layouts = parse_default ();133 }
134 134
135 validate ();135 private void switch_items (uint pos1, uint pos2) {
136 }136 unowned List<Layout> container1 = layouts.nth (pos1);
137 }137 unowned List<Layout> container2 = layouts.nth (pos2);
138 138 Layout tmp = container1.data;
139 // allows for multiple kayboard layouts at a time139 container1.data = container2.data;
140 class SettingsGroups : Granite.Services.Settings140 container2.data = tmp;
141 {141
142 public int default_group { get; set; }142 if (active == pos1)
143 public bool group_per_window { get; set; }143 active = pos2;
144 144 else if (active == pos2)
145 public void reset_all ()145 active = pos1;
146 {146
147 schema.reset ("default-group");147 layouts_changed ();
148 schema.reset ("group-per-window"); 148 }
149 }149
150 150 public void move_active_layout_up () {
151 public SettingsGroups()151 if (length == 0)
152 {152 return;
153 base ("org.gnome.libgnomekbd.desktop");153
154 }154 // check that the active item is not the first one
155 }155 if (active > 0) {
156 switch_items (active, active - 1);
157 }
158 }
159
160 public void move_active_layout_down () {
161 if (length == 0)
162 return;
163
164 // check that the active item is not the last one
165 if (active < length - 1) {
166 switch_items (active, active + 1);
167 }
168 }
169
170 public bool add_layout (Layout new_layout) {
171 if (! contains_layout (new_layout)) {
172 layouts.append (new_layout);
173 layouts_changed ();
174 return true;
175 }
176 return false;
177 }
178
179 public void remove_active_layout () {
180 layouts.remove (get_layout (active));
181
182 if (active >= length)
183 active = length - 1;
184 layouts_changed ();
185 }
186
187 public void remove_all () {
188 layouts = new GLib.List<Layout> ();
189 layouts_changed ();
190 }
191
192 /**
193 * This method does not need call layouts_changed in any situation
194 * as a Layout-Object is immutable.
195 */
196 public Layout? get_layout (uint index) {
197 if (index >= length)
198 return null;
199
200 return layouts.nth_data (index);
201 }
202
203 }
204
205 class LayoutSettings
206 {
207
208 public LayoutList layouts { get; private set; }
209
210 GLib.Settings settings;
211
212 /**
213 * True if and only if we are currently writing to gsettings
214 * by ourselves.
215 */
216 bool currently_writing;
217
218 void write_list_to_gsettings () {
219 currently_writing = true;
220 try {
221 Variant[] elements = {};
222 for (uint i = 0; i < layouts.length; i++) {
223 elements += layouts.get_layout (i).to_variant ();
224 }
225 GLib.Variant list = new GLib.Variant.array (new VariantType ("(ss)"), elements);
226 settings.set_value ("sources", list);
227 } finally {
228 currently_writing = false;
229 }
230 }
231
232 void write_active_to_gsettings () {
233 uint active = layouts.active;
234 settings.set_uint ("current", active);
235 }
236
237 void update_list_from_gsettings () {
238 // We currently write to gsettings, so we caused this signal
239 // and therefore don't need to read the list again from dconf
240 if (currently_writing)
241 return;
242
243 GLib.Variant sources = settings.get_value ("sources");
244 if (sources.is_of_type (VariantType.ARRAY)) {
245 for(size_t i = 0; i < sources.n_children (); i++) {
246 GLib.Variant child = sources.get_child_value (i);
247 layouts.add_layout (new Layout.from_variant (child));
248 }
249 } else {
250 warning ("Unkown type");
251 }
252 }
253
254 void update_active_from_gsettings () {
255 layouts.active = settings.get_uint ("current");
256 }
257
258 bool _per_window;
259 public bool per_window {
260 get {
261 return _per_window;
262 }
263 set {
264 if (value != _per_window) {
265 settings.set_boolean ("per-window", value);
266 _per_window = value;
267 }
268 }
269 }
270 // signal when the variable per_window is changed by gsettings
271 public signal void per_window_changed ();
272
273 public void parse_default () {
274 var file = File.new_for_path ("/etc/default/keyboard");
275
276 if (!file.query_exists ()) {
277 warning ("File '%s' doesn't exist.\n", file.get_path ());
278 return;
279 }
280
281 string xkb_layout = "";
282 string xkb_variant = "";
283
284 try {
285 var dis = new DataInputStream (file.read ());
286
287 string line;
288
289 while ((line = dis.read_line (null)) != null)
290 {
291 if (line.contains ("XKBLAYOUT="))
292 {
293 xkb_layout = line.replace ("XKBLAYOUT=", "").replace ("\"", "");
294
295 while ((line = dis.read_line (null)) != null) {
296 if (line.contains ("XKBVARIANT=")) {
297 xkb_variant = line.replace ("XKBVARIANT=", "").replace ("\"", "");
298 }
299 }
300
301 break;
302 }
303 }
304 }
305 catch (Error e) {
306 warning ("%s", e.message);
307 return;
308 }
309
310 var variants = xkb_variant.split (",");
311 var xkb_layouts = xkb_layout.split (",");
312
313 for (int i = 0; i < layouts.length; i++) {
314 if (variants[i] != null && variants[i] != "")
315 layouts.add_layout (new Layout (LayoutType.XKB, xkb_layouts[i] + "+" + variants[i]));
316 else
317 layouts.add_layout (new Layout (LayoutType.XKB, xkb_layouts[i]));
318 }
319 }
320
321 public void reset_all ()
322 {
323 layouts.remove_all ();
324 parse_default ();
325 }
326
327 // singleton pattern
328 static LayoutSettings? instance;
329 public static LayoutSettings get_instance () {
330 if (instance == null) {
331 instance = new LayoutSettings ();
332 }
333 return instance;
334 }
335
336 private LayoutSettings ()
337 {
338 settings = new Settings ("org.gnome.desktop.input-sources");
339 layouts = new LayoutList ();
340
341 _per_window = settings.get_boolean ("per-window");
342 settings.changed["per-window"].connect (() => {
343 _per_window = settings.get_boolean ("per-window");
344 per_window_changed ();
345 });
346
347 update_list_from_gsettings ();
348 update_active_from_gsettings ();
349
350 layouts.layouts_changed.connect (() => {
351 write_list_to_gsettings ();
352 });
353
354 layouts.active_changed.connect (() => {
355 write_active_to_gsettings ();
356 });
357
358 settings.changed["sources"].connect (() => {
359 update_list_from_gsettings ();
360 });
361
362 settings.changed["current"].connect (() => {
363 update_active_from_gsettings ();
364 });
365
366 if (layouts.length == 0)
367 parse_default ();
368
369 }
370 }
371
156}372}
157\ No newline at end of file373\ No newline at end of file
158374
=== modified file 'src/Pages/layout.vala'
--- src/Pages/layout.vala 2014-01-06 17:12:27 +0000
+++ src/Pages/layout.vala 2014-08-11 14:54:46 +0000
@@ -1,12 +1,12 @@
1namespace Pantheon.Keyboard.Layout1namespace Pantheon.Keyboard.LayoutPage
2{2{
3 // global handler3 // global handler
4 LayoutHandler handler;4 LayoutHandler handler;
55
6 class Page : Pantheon.Keyboard.AbstractPage6 class Page : Pantheon.Keyboard.AbstractPage
7 {7 {
8 private Layout.Display display;8 private LayoutPage.Display display;
9 private SettingsGroups settings;9 private LayoutSettings settings;
1010
11 public override void reset ()11 public override void reset ()
12 {12 {
@@ -18,18 +18,14 @@
18 public Page ()18 public Page ()
19 {19 {
20 handler = new LayoutHandler ();20 handler = new LayoutHandler ();
21 settings = LayoutSettings.get_instance ();
2122
22 // first some labels23 // first some labels
23 var label_1 = new Gtk.Label (_("Allow different layouts for individual windows:"));24 var label_1 = new Gtk.Label (_("Allow different layouts for individual windows:"));
24 var label_2 = new Gtk.Label (_("New windows use:"));
2525
26 label_1.valign = Gtk.Align.CENTER;26 label_1.valign = Gtk.Align.CENTER;
27 label_1.halign = Gtk.Align.END;27 label_1.halign = Gtk.Align.END;
28 label_2.valign = Gtk.Align.CENTER;
29 label_2.halign = Gtk.Align.END;
30
31 this.attach (label_1, 4, 0, 1, 1);28 this.attach (label_1, 4, 0, 1, 1);
32 this.attach (label_2, 4, 1, 1, 1);
3329
34 // widgets to change settings30 // widgets to change settings
35 var switch_main = new Gtk.Switch();31 var switch_main = new Gtk.Switch();
@@ -37,52 +33,20 @@
37 switch_main.halign = Gtk.Align.START;33 switch_main.halign = Gtk.Align.START;
38 switch_main.valign = Gtk.Align.CENTER;34 switch_main.valign = Gtk.Align.CENTER;
3935
40 var button1 = new Gtk.RadioButton.with_label(null, _("Default layout"));
41 var button2 = new Gtk.RadioButton.with_label_from_widget (button1, _("Previous window's layout"));
42
43 this.attach (switch_main, 5, 0, 1, 1);36 this.attach (switch_main, 5, 0, 1, 1);
44 this.attach (button1, 5, 1, 1, 1);37
45 this.attach (button2, 5, 2, 1, 1);38 switch_main.active = settings.per_window;
4639
47 settings = new Layout.SettingsGroups();40 switch_main.notify["active"].connect(() => {
4841 settings.per_window = switch_main.active;
49 // connect switch signals42 });
50 switch_main.active = settings.group_per_window;43 settings.per_window_changed.connect (() => {
5144 switch_main.active = settings.per_window;
52 button1.sensitive = button2.sensitive = switch_main.active;45 });
53 label_2.sensitive = switch_main.active;46
54
55 switch_main.notify["active"].connect( () => {
56 settings.group_per_window = switch_main.active;
57 button1.sensitive = button2.sensitive = switch_main.active;
58 label_2.sensitive = switch_main.active;
59 } );
60
61 settings.changed["group-per-window"].connect (() => {
62 switch_main.active = settings.group_per_window;
63 button1.sensitive = button2.sensitive = switch_main.active;
64 label_2.sensitive = switch_main.active;
65 } );
66
67 // connect radio button signals
68 if( settings.default_group >= 0 )
69 button1.active = true;
70 else
71 button2.active = true;
72
73 button1.toggled.connect (() => { settings.default_group = 0; } );
74 button2.toggled.connect (() => { settings.default_group = -1; } );
75
76 settings.changed["default-group"].connect (() =>
77 {
78 if( settings.default_group >= 0 )
79 button1.active = true;
80 else
81 button2.active = true;
82 } );
8347
84 // tree view to display the current layouts48 // tree view to display the current layouts
85 display = new Layout.Display ();49 display = new LayoutPage.Display ();
8650
87 this.attach (display, 0, 0, 4, 4);51 this.attach (display, 0, 0, 4, 4);
8852
8953
=== modified file 'src/keyboard.vala'
--- src/keyboard.vala 2014-08-03 01:16:31 +0000
+++ src/keyboard.vala 2014-08-11 14:54:46 +0000
@@ -17,41 +17,31 @@
17 var stack_switcher = new Gtk.StackSwitcher ();17 var stack_switcher = new Gtk.StackSwitcher ();
18 stack_switcher.set_stack (stack);18 stack_switcher.set_stack (stack);
19 stack_switcher.halign = Gtk.Align.CENTER;19 stack_switcher.halign = Gtk.Align.CENTER;
20 20
21 stack.add_titled (new Keyboard.Shortcuts.Page (), "shortcuts", _("Shortcuts"));21 stack.add_titled (new Keyboard.Shortcuts.Page (), "shortcuts", _("Shortcuts"));
22 stack.add_titled (new Keyboard.Behaviour.Page (), "behavior", _("Behavior"));22 stack.add_titled (new Keyboard.Behaviour.Page (), "behavior", _("Behavior"));
23 stack.add_titled (new Keyboard.Layout.Page (), "layout", _("Layout"));23 stack.add_titled (new Keyboard.LayoutPage.Page (), "layout", _("Layout"));
24 stack.add_titled (new Keyboard.Options.Page (), "options", _("Options"));24 stack.add_titled (new Keyboard.Options.Page (), "options", _("Options"));
2525
26 // button to reset the current page
27 /*var button = new Gtk.Button.with_label (_("Reset to defaults"));
28
29 button.expand = false;
30 button.halign = Gtk.Align.END;
31
32 button.clicked.connect (() => {
33 pages[notebook.page].reset ();
34 });*/
35
36 grid.attach (stack_switcher, 0, 0, 1, 1);26 grid.attach (stack_switcher, 0, 0, 1, 1);
37 grid.attach (stack, 0, 1, 1, 1);27 grid.attach (stack, 0, 1, 1, 1);
38 }28 }
39 grid.show_all ();29 grid.show_all ();
40 return grid;30 return grid;
41 }31 }
42 32
43 public override void shown () {33 public override void shown () {
44 34
45 }35 }
46 36
47 public override void hidden () {37 public override void hidden () {
48 38
49 }39 }
50 40
51 public override void search_callback (string location) {41 public override void search_callback (string location) {
52 42
53 }43 }
54 44
55 // 'search' returns results like ("Keyboard → Behavior → Duration", "keyboard<sep>behavior")45 // 'search' returns results like ("Keyboard → Behavior → Duration", "keyboard<sep>behavior")
56 public override async Gee.TreeMap<string, string> search (string search) {46 public override async Gee.TreeMap<string, string> search (string search) {
57 return new Gee.TreeMap<string, string> (null, null);47 return new Gee.TreeMap<string, string> (null, null);
@@ -62,4 +52,4 @@
62 debug ("Activating Keyboard plug");52 debug ("Activating Keyboard plug");
63 var plug = new Pantheon.Keyboard.Plug ();53 var plug = new Pantheon.Keyboard.Plug ();
64 return plug;54 return plug;
65}55}
66\ No newline at end of file56\ No newline at end of file

Subscribers

People subscribed via source and target branches

to all changes: