Merge lp:~julien-spautz/switchboard-plug-keyboard/custom-shortcuts into lp:~elementary-pantheon/switchboard-plug-keyboard/trunk
- custom-shortcuts
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 325 | ||||
Proposed branch: | lp:~julien-spautz/switchboard-plug-keyboard/custom-shortcuts | ||||
Merge into: | lp:~elementary-pantheon/switchboard-plug-keyboard/trunk | ||||
Diff against target: |
971 lines (+550/-233) 12 files modified
src/CMakeLists.txt (+4/-0) src/Pages/Shortcuts/conflict_dialog.vala (+19/-0) src/Pages/Shortcuts/custom_shortcut_settings.vala (+146/-0) src/Pages/Shortcuts/custom_tree.vala (+178/-0) src/Pages/Shortcuts/display.vala (+23/-11) src/Pages/Shortcuts/display_tree.vala (+5/-0) src/Pages/Shortcuts/list.vala (+1/-26) src/Pages/Shortcuts/section_switcher.vala (+6/-3) src/Pages/Shortcuts/settings.vala (+1/-1) src/Pages/Shortcuts/shortcut.vala (+2/-2) src/Pages/Shortcuts/tree.vala (+144/-181) src/Pages/shortcuts.vala (+21/-9) |
||||
To merge this branch: | bzr merge lp:~julien-spautz/switchboard-plug-keyboard/custom-shortcuts | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Raphael Isemann (community) | code style, functionality | Needs Fixing | |
Artem Anufrij (community) | code style | Needs Fixing | |
Danielle Foré | Needs Fixing | ||
David Gomes (community) | Needs Fixing | ||
Review via email: mp+212343@code.launchpad.net |
Commit message
Description of the change
Now open for review.
Implemented custom shortcuts into the keyboard plug. I'm using dconf/gsettings instead of gconf (unlike elementary tweaks) since the gconf version doesn't seem to work on isis, also it's deprecated.
Custom shortcuts can be added/removed/
If the schema for custom shortcuts doesn't exist, the section will not be shown at all.
Conflicting shortcuts are handled like before, asking the user whether he wants to reassign the shortcut.
NOTE that changes to custom shortcuts will, for some reason, not be applied immediately but you'll have to log out and in again, reboot or restart gnome-settings-
- 136. By Julien Spautz
-
small refactor: using DisplayTree instead of GtkTree to avoid casting
- 137. By Julien Spautz
-
remove some unused code
- 138. By Julien Spautz
-
fixed failing assertions on clearing shortcuts
- 139. By Julien Spautz
-
fix inconsistent whitespace
Julien Spautz (julien-spautz) wrote : | # |
Completely forgot about the whitespace... Following files should now follow elementary's coding guidelines, all other files should still be internally consistent:
src/Pages/
src/Pages/
src/Pages/
src/Pages/
src/Pages/
(The four first files are new, the last one isn't, but I had to change a lot of code in that one so I converted it to elementary code)
- 140. By Julien Spautz
-
fixed small inconsistency in whitespace
David Gomes (davidgomes) wrote : | # |
I can't seem to build this. First I got:
`
/usr/bin/msgfmt: error while opening "/home/
`
So I ran it with root privileges and got: http://
Julien Spautz (julien-spautz) wrote : | # |
built it on freya beta 1 and it works for me, can someone test it again?
Danielle Foré (danrabbit) wrote : | # |
Shortcuts don't seem to apply until I log out and log back in. Is there any way to make these apply immediately? (restart/update whatever service is responsible for watching for shortcuts?)
If not, we should at least show an infobar stating that you'll need to log out or restart for the changes to take effect.
Danielle Foré (danrabbit) wrote : | # |
The "-" button shouldn't be sensitive if there is no line selected
Artem Anufrij (artem-anufrij) wrote : | # |
see line comments
Raphael Isemann (teemperor) wrote : | # |
As Daniel said, you shouln't need to relog/reboot for the keybindings to take effect, so just set "org.gnome.
Interestingly on my system if i do this noise seems to loose the binding to the next/previous keys on my keyboard until i restart noise. But i think that's rather a bug in noise itself?
Otherwise:
* Commented-out code in line 780-781.
* Line 417: tbar = new Gtk.Toolbar(); <- needs a blank before the bracket
Preview Diff
1 | === modified file 'src/CMakeLists.txt' |
2 | --- src/CMakeLists.txt 2014-01-10 08:17:09 +0000 |
3 | +++ src/CMakeLists.txt 2014-03-30 21:21:15 +0000 |
4 | @@ -29,6 +29,10 @@ |
5 | Pages/Shortcuts/shortcut.vala |
6 | Pages/Shortcuts/list.vala |
7 | Pages/Shortcuts/section_switcher.vala |
8 | + Pages/Shortcuts/custom_tree.vala |
9 | + Pages/Shortcuts/custom_shortcut_settings.vala |
10 | + Pages/Shortcuts/conflict_dialog.vala |
11 | + Pages/Shortcuts/display_tree.vala |
12 | |
13 | Pages/layout.vala |
14 | Pages/Layout/display.vala |
15 | |
16 | === added file 'src/Pages/Shortcuts/conflict_dialog.vala' |
17 | --- src/Pages/Shortcuts/conflict_dialog.vala 1970-01-01 00:00:00 +0000 |
18 | +++ src/Pages/Shortcuts/conflict_dialog.vala 2014-03-30 21:21:15 +0000 |
19 | @@ -0,0 +1,19 @@ |
20 | +class ConflictDialog : Gtk.MessageDialog { |
21 | + |
22 | + public signal void reassign (); |
23 | + |
24 | + public ConflictDialog (string shortcut, string conflict_action, string this_action) { |
25 | + modal = true; |
26 | + message_type = Gtk.MessageType.WARNING; |
27 | + text = @"\"$shortcut\" is already used for \"$conflict_action\"!"; |
28 | + secondary_text = _(@"If you reassign the shortcut to \"$this_action\", \"$conflict_action\" will be disabled"); |
29 | + add_button (_("Cancel"), 0); |
30 | + add_button (_("Reassign"), 1); |
31 | + |
32 | + response.connect ((response_id) => { |
33 | + if (response_id == 1) |
34 | + reassign (); |
35 | + destroy(); |
36 | + }); |
37 | + } |
38 | +} |
39 | \ No newline at end of file |
40 | |
41 | === added file 'src/Pages/Shortcuts/custom_shortcut_settings.vala' |
42 | --- src/Pages/Shortcuts/custom_shortcut_settings.vala 1970-01-01 00:00:00 +0000 |
43 | +++ src/Pages/Shortcuts/custom_shortcut_settings.vala 2014-03-30 21:21:15 +0000 |
44 | @@ -0,0 +1,146 @@ |
45 | +class Pantheon.Keyboard.Shortcuts.CustomShortcutSettings : Object { |
46 | + |
47 | + const string SCHEMA = "org.gnome.settings-daemon.plugins.media-keys"; |
48 | + const string KEY = "custom-keybinding"; |
49 | + |
50 | + const string RELOCATABLE_SCHEMA_PATH_TEMLPATE = "/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom%d/"; |
51 | + |
52 | + const int MAX_SHORTCUTS = 100; |
53 | + |
54 | + static GLib.Settings settings; |
55 | + |
56 | + public static bool available = false; |
57 | + |
58 | + public struct CustomShortcut { |
59 | + string shortcut; |
60 | + string command; |
61 | + string relocatable_schema; |
62 | + } |
63 | + |
64 | + public static void init () { |
65 | + var schema_source = GLib.SettingsSchemaSource.get_default (); |
66 | + |
67 | + var schema = schema_source.lookup (SCHEMA, true); |
68 | + |
69 | + if (schema == null) { |
70 | + warning ("Schema \"%s\" is not installed on your system.", SCHEMA); |
71 | + return; |
72 | + } |
73 | + |
74 | + settings = new GLib.Settings.full (schema, null, null); |
75 | + available = true; |
76 | + } |
77 | + |
78 | + static string[] get_relocatable_schemas () { |
79 | + return settings.get_strv (KEY + "s"); |
80 | + } |
81 | + |
82 | + static string get_relocatable_schema_path (int i) { |
83 | + return RELOCATABLE_SCHEMA_PATH_TEMLPATE.printf (i); |
84 | + } |
85 | + |
86 | + static GLib.Settings? get_relocatable_schema_settings (string relocatable_schema) { |
87 | + return new GLib.Settings.with_path (SCHEMA + "." + KEY, relocatable_schema); |
88 | + } |
89 | + |
90 | + public static string? create_shortcut () requires (available) { |
91 | + for (int i = 0; i < MAX_SHORTCUTS; i++) { |
92 | + var new_relocatable_schema = get_relocatable_schema_path (i); |
93 | + |
94 | + if (relocatable_schema_is_used (new_relocatable_schema) == false) { |
95 | + add_relocatable_schema (new_relocatable_schema); |
96 | + reset_relocatable_schema (new_relocatable_schema); |
97 | + return new_relocatable_schema; |
98 | + } |
99 | + } |
100 | + |
101 | + return (string) null; |
102 | + } |
103 | + |
104 | + static bool relocatable_schema_is_used (string new_relocatable_schema) { |
105 | + var relocatable_schemas = get_relocatable_schemas (); |
106 | + |
107 | + foreach (var relocatable_schema in relocatable_schemas) |
108 | + if (relocatable_schema == new_relocatable_schema) |
109 | + return true; |
110 | + |
111 | + return false; |
112 | + } |
113 | + |
114 | + static void add_relocatable_schema (string new_relocatable_schema) { |
115 | + var relocatable_schemas = get_relocatable_schemas (); |
116 | + relocatable_schemas += new_relocatable_schema; |
117 | + settings.set_strv (KEY + "s", relocatable_schemas); |
118 | + } |
119 | + |
120 | + static void reset_relocatable_schema (string relocatable_schema) { |
121 | + var relocatable_settings = get_relocatable_schema_settings (relocatable_schema); |
122 | + relocatable_settings.reset ("name"); |
123 | + relocatable_settings.reset ("command"); |
124 | + relocatable_settings.reset ("binding"); |
125 | + } |
126 | + |
127 | + public static void remove_shortcut (string relocatable_schema) |
128 | + requires (available) { |
129 | + |
130 | + string []relocatable_schemas = {}; |
131 | + |
132 | + foreach (var schema in get_relocatable_schemas ()) |
133 | + if (schema != relocatable_schema) |
134 | + relocatable_schemas += schema; |
135 | + |
136 | + reset_relocatable_schema (relocatable_schema); |
137 | + settings.set_strv (KEY + "s", relocatable_schemas); |
138 | + } |
139 | + |
140 | + public static bool edit_shortcut (string relocatable_schema, string shortcut) |
141 | + requires (available) { |
142 | + |
143 | + var relocatable_settings = get_relocatable_schema_settings (relocatable_schema); |
144 | + relocatable_settings.set_string ("binding", shortcut); |
145 | + return true; |
146 | + } |
147 | + |
148 | + public static bool edit_command (string relocatable_schema, string command) |
149 | + requires (available) { |
150 | + |
151 | + var relocatable_settings = get_relocatable_schema_settings (relocatable_schema); |
152 | + relocatable_settings.set_string ("command", command); |
153 | + return true; |
154 | + } |
155 | + |
156 | + public static GLib.List <CustomShortcut?> list_custom_shortcuts () |
157 | + requires (available) { |
158 | + |
159 | + var list = new GLib.List <CustomShortcut?> (); |
160 | + foreach (var relocatable_schema in get_relocatable_schemas ()) |
161 | + list.append (create_custom_shortcut_object (relocatable_schema)); |
162 | + return list; |
163 | + } |
164 | + |
165 | + static CustomShortcut? create_custom_shortcut_object (string relocatable_schema) { |
166 | + var relocatable_settings = get_relocatable_schema_settings (relocatable_schema); |
167 | + |
168 | + return { |
169 | + relocatable_settings.get_string ("binding"), |
170 | + relocatable_settings.get_string ("command"), |
171 | + relocatable_schema |
172 | + }; |
173 | + } |
174 | + |
175 | + public static bool shortcut_conflicts (Shortcut new_shortcut, out string command, |
176 | + out string relocatable_schema) { |
177 | + var custom_shortcuts = list_custom_shortcuts (); |
178 | + |
179 | + foreach (var custom_shortcut in custom_shortcuts) { |
180 | + var shortcut = new Shortcut.parse (custom_shortcut.shortcut); |
181 | + if (shortcut.is_equal (new_shortcut)) { |
182 | + command = custom_shortcut.command; |
183 | + relocatable_schema = custom_shortcut.relocatable_schema; |
184 | + return true; |
185 | + } |
186 | + } |
187 | + |
188 | + return false; |
189 | + } |
190 | +} |
191 | \ No newline at end of file |
192 | |
193 | === added file 'src/Pages/Shortcuts/custom_tree.vala' |
194 | --- src/Pages/Shortcuts/custom_tree.vala 1970-01-01 00:00:00 +0000 |
195 | +++ src/Pages/Shortcuts/custom_tree.vala 2014-03-30 21:21:15 +0000 |
196 | @@ -0,0 +1,178 @@ |
197 | +private class Pantheon.Keyboard.Shortcuts.CustomTree : Gtk.TreeView, DisplayTree { |
198 | + |
199 | + Gtk.CellRendererText cell_desc; |
200 | + Gtk.CellRendererAccel cell_edit; |
201 | + |
202 | + enum Column { |
203 | + COMMAND, |
204 | + SHORTCUT, |
205 | + SCHEMA, |
206 | + COUNT |
207 | + } |
208 | + |
209 | + public CustomTree () { |
210 | + setup_gui (); |
211 | + load_and_display_custom_shortcuts (); |
212 | + connect_signals (); |
213 | + } |
214 | + |
215 | + Gtk.ListStore list_store { |
216 | + get { return model as Gtk.ListStore; } |
217 | + } |
218 | + |
219 | + void setup_gui () { |
220 | + var store = new Gtk.ListStore (Column.COUNT , typeof (string), |
221 | + typeof (string), |
222 | + typeof (string)); |
223 | + |
224 | + cell_desc = new Gtk.CellRendererText (); |
225 | + cell_edit = new Gtk.CellRendererAccel (); |
226 | + |
227 | + cell_desc.editable = true; |
228 | + cell_edit.editable = true; |
229 | + cell_edit.accel_mode = Gtk.CellRendererAccelMode.OTHER; |
230 | + |
231 | + this.set_model (store); |
232 | + |
233 | + this.insert_column_with_attributes (-1, _("Command"), cell_desc, "markup", Column.COMMAND); |
234 | + this.insert_column_with_attributes (-1, _("Shortcut"), cell_edit, "text", Column.SHORTCUT); |
235 | + |
236 | + this.expand = true; |
237 | + this.get_column (0).expand = true; |
238 | + } |
239 | + |
240 | + public void load_and_display_custom_shortcuts () { |
241 | + Gtk.TreeIter iter; |
242 | + var store = new Gtk.ListStore (Column.COUNT , typeof (string), |
243 | + typeof (string), |
244 | + typeof (string)); |
245 | + |
246 | + foreach (var custom_shortcut in CustomShortcutSettings.list_custom_shortcuts ()) { |
247 | + var shortcut = new Shortcut.parse (custom_shortcut.shortcut); |
248 | + |
249 | + store.append (out iter); |
250 | + store.set (iter, |
251 | + Column.COMMAND, command_to_display (custom_shortcut.command), |
252 | + Column.SHORTCUT, shortcut.to_readable (), |
253 | + Column.SCHEMA, custom_shortcut.relocatable_schema |
254 | + ); |
255 | + } |
256 | + |
257 | + model = store; |
258 | + } |
259 | + |
260 | + void connect_signals () { |
261 | + this.button_press_event.connect ((event) => { |
262 | + if (event.window != this.get_bin_window ()) |
263 | + return false; |
264 | + |
265 | + Gtk.TreePath path; |
266 | + Gtk.TreeViewColumn col; |
267 | + |
268 | + if (this.get_path_at_pos ((int) event.x, (int) event.y, |
269 | + out path, out col, null, null)) { |
270 | + this.grab_focus (); |
271 | + this.set_cursor (path, col, true); |
272 | + } |
273 | + |
274 | + return true; |
275 | + }); |
276 | + |
277 | + cell_edit.accel_edited.connect ((path, key, mods) => { |
278 | + var shortcut = new Shortcut (key, mods); |
279 | + change_shortcut (path, shortcut); |
280 | + }); |
281 | + |
282 | + cell_edit.accel_cleared.connect ((path) => { |
283 | + change_shortcut (path, (Shortcut) null); |
284 | + }); |
285 | + |
286 | + cell_desc.edited.connect (change_command); |
287 | + } |
288 | + |
289 | + string command_to_display (string? command) { |
290 | + if (command == null || command.strip () == "") |
291 | + return "<i>" +_("Enter Command") + "</i>"; |
292 | + return GLib.Markup.escape_text (command); |
293 | + } |
294 | + |
295 | + public void on_add_clicked () { |
296 | + var store = model as Gtk.ListStore; |
297 | + Gtk.TreeIter iter; |
298 | + |
299 | + var relocatable_schema = CustomShortcutSettings.create_shortcut (); |
300 | + |
301 | + store.append (out iter); |
302 | + store.set (iter, Column.COMMAND, command_to_display (null)); |
303 | + store.set (iter, Column.SHORTCUT, (new Shortcut.parse ("")).to_readable ()); |
304 | + store.set (iter, Column.SCHEMA, relocatable_schema); |
305 | + } |
306 | + |
307 | + public void on_remove_clicked () { |
308 | + Gtk.TreeIter iter; |
309 | + Gtk.TreePath path; |
310 | + GLib.Value relocatable_schema; |
311 | + |
312 | + get_cursor (out path, null); |
313 | + model.get_iter (out iter, path); |
314 | + model.get_value (iter, Column.SCHEMA, out relocatable_schema); |
315 | + |
316 | + CustomShortcutSettings.remove_shortcut ((string) relocatable_schema); |
317 | + list_store.remove (iter); |
318 | + } |
319 | + |
320 | + void change_command (string path, string new_text) { |
321 | + Gtk.TreeIter iter; |
322 | + GLib.Value relocatable_schema; |
323 | + |
324 | + model.get_iter (out iter, new Gtk.TreePath.from_string (path)); |
325 | + model.get_value (iter, Column.SCHEMA, out relocatable_schema); |
326 | + |
327 | + CustomShortcutSettings.edit_command ((string) relocatable_schema, new_text); |
328 | + load_and_display_custom_shortcuts (); |
329 | + } |
330 | + |
331 | + public bool shortcut_conflicts (Shortcut shortcut, out string name) { |
332 | + return CustomShortcutSettings.shortcut_conflicts (shortcut, out name, null); |
333 | + } |
334 | + |
335 | + public void reset_shortcut (Shortcut shortcut) { |
336 | + string relocatable_schema; |
337 | + CustomShortcutSettings.shortcut_conflicts (shortcut, null, out relocatable_schema); |
338 | + CustomShortcutSettings.edit_shortcut (relocatable_schema, ""); |
339 | + load_and_display_custom_shortcuts (); |
340 | + } |
341 | + |
342 | + bool change_shortcut (string path, Shortcut? shortcut) { |
343 | + Gtk.TreeIter iter; |
344 | + GLib.Value command, relocatable_schema; |
345 | + |
346 | + model.get_iter (out iter, new Gtk.TreePath.from_string (path)); |
347 | + model.get_value (iter, Column.SCHEMA, out relocatable_schema); |
348 | + model.get_value (iter, Column.COMMAND, out command); |
349 | + |
350 | + var not_null_shortcut = shortcut ?? new Shortcut (); |
351 | + |
352 | + string conflict_name; |
353 | + |
354 | + if (shortcut != null) { |
355 | + foreach (var tree in trees) { |
356 | + if (tree.shortcut_conflicts (shortcut, out conflict_name) == false) |
357 | + continue; |
358 | + |
359 | + var dialog = new ConflictDialog (shortcut.to_readable (), conflict_name, (string) command); |
360 | + dialog.reassign.connect (() => { |
361 | + tree.reset_shortcut (shortcut); |
362 | + CustomShortcutSettings.edit_shortcut ((string) relocatable_schema, not_null_shortcut.to_gsettings ()); |
363 | + load_and_display_custom_shortcuts (); |
364 | + }); |
365 | + dialog.show (); |
366 | + return false; |
367 | + } |
368 | + } |
369 | + |
370 | + CustomShortcutSettings.edit_shortcut ((string) relocatable_schema, not_null_shortcut.to_gsettings ()); |
371 | + load_and_display_custom_shortcuts (); |
372 | + return true; |
373 | + } |
374 | +} |
375 | \ No newline at end of file |
376 | |
377 | === modified file 'src/Pages/Shortcuts/display.vala' |
378 | --- src/Pages/Shortcuts/display.vala 2014-01-06 17:12:27 +0000 |
379 | +++ src/Pages/Shortcuts/display.vala 2014-03-30 21:21:15 +0000 |
380 | @@ -1,3 +1,4 @@ |
381 | +// TODO use new Gtk.Stack widget here |
382 | namespace Pantheon.Keyboard.Shortcuts |
383 | { |
384 | // creates a grid containing a tree view and an inline toolbar |
385 | @@ -6,16 +7,17 @@ |
386 | int selected; |
387 | |
388 | Gtk.ScrolledWindow scroll; |
389 | - Tree[] trees; |
390 | - |
391 | - public ShortcutDisplay (Tree[] t) |
392 | + DisplayTree[] trees; |
393 | + |
394 | + Gtk.Toolbar tbar; |
395 | + |
396 | + public ShortcutDisplay (DisplayTree[] t) |
397 | { |
398 | selected = 0; |
399 | |
400 | - trees = t; |
401 | - |
402 | - foreach (var tree in trees) { |
403 | + foreach (var tree in t) { |
404 | tree.set_rules_hint (true); |
405 | + trees += tree; |
406 | } |
407 | |
408 | scroll = new Gtk.ScrolledWindow(null, null); |
409 | @@ -23,14 +25,15 @@ |
410 | scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC; |
411 | scroll.shadow_type = Gtk.ShadowType.IN; |
412 | scroll.expand = true; |
413 | - scroll.add (trees[selected]); |
414 | + scroll.add (t[selected]); |
415 | |
416 | - var tbar = new Gtk.Toolbar(); |
417 | + tbar = new Gtk.Toolbar(); |
418 | tbar.set_style(Gtk.ToolbarStyle.ICONS); |
419 | tbar.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR); |
420 | tbar.set_show_arrow(false); |
421 | tbar.hexpand = true; |
422 | - |
423 | + tbar.no_show_all = true; |
424 | + |
425 | scroll.get_style_context().set_junction_sides(Gtk.JunctionSides.BOTTOM); |
426 | tbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR); |
427 | tbar.get_style_context().set_junction_sides(Gtk.JunctionSides.TOP); |
428 | @@ -48,7 +51,12 @@ |
429 | tbar.insert (remove_button, -1); |
430 | |
431 | this.attach (scroll, 0, 0, 1, 1); |
432 | - //this.attach (tbar, 0, 1, 1, 1); |
433 | + this.attach (tbar, 0, 1, 1, 1); |
434 | + |
435 | + add_button.clicked.connect (() => |
436 | + (trees[selected] as CustomTree).on_add_clicked ()); |
437 | + remove_button.clicked.connect (() => |
438 | + (trees[selected] as CustomTree).on_remove_clicked ()); |
439 | } |
440 | |
441 | // replace old tree view with new one |
442 | @@ -58,7 +66,11 @@ |
443 | scroll.add (trees[new_selection]); |
444 | |
445 | selected = new_selection; |
446 | - scroll.show_all (); |
447 | + |
448 | + tbar.no_show_all = new_selection != SectionID.CUSTOM; |
449 | + tbar.visible = new_selection == SectionID.CUSTOM; |
450 | + |
451 | + show_all (); |
452 | |
453 | return true; |
454 | } |
455 | |
456 | === added file 'src/Pages/Shortcuts/display_tree.vala' |
457 | --- src/Pages/Shortcuts/display_tree.vala 1970-01-01 00:00:00 +0000 |
458 | +++ src/Pages/Shortcuts/display_tree.vala 2014-03-30 21:21:15 +0000 |
459 | @@ -0,0 +1,5 @@ |
460 | +interface Pantheon.Keyboard.Shortcuts.DisplayTree : Gtk.TreeView { |
461 | + |
462 | + public abstract bool shortcut_conflicts (Shortcut shortcut, out string name); |
463 | + public abstract void reset_shortcut (Shortcut shortcut); |
464 | +} |
465 | \ No newline at end of file |
466 | |
467 | === modified file 'src/Pages/Shortcuts/list.vala' |
468 | --- src/Pages/Shortcuts/list.vala 2014-03-12 08:11:41 +0000 |
469 | +++ src/Pages/Shortcuts/list.vala 2014-03-30 21:21:15 +0000 |
470 | @@ -21,31 +21,6 @@ |
471 | return; |
472 | } |
473 | |
474 | - public bool conflicts (Shortcut s, out string key, out int group, out int path) |
475 | - { |
476 | - key = (string) null; |
477 | - group = (SectionID) 0; |
478 | - path = -1; |
479 | - |
480 | - if (s.accel_key == Gdk.Key.BackSpace) |
481 | - return false; |
482 | - |
483 | - for (int g = 0; g < groups.length; g++) |
484 | - { |
485 | - for (int i = 0; i < groups[g].actions.length; i++) |
486 | - { |
487 | - if (s.is_equal (settings.get_val(groups[g].schemas[i], groups[g].keys[i]))) |
488 | - { |
489 | - key = groups[g].keys[i]; |
490 | - group = g; |
491 | - path = i; |
492 | - return true; |
493 | - } |
494 | - } |
495 | - } |
496 | - return false; |
497 | - } |
498 | - |
499 | public List () |
500 | { |
501 | groups = |
502 | @@ -70,7 +45,7 @@ |
503 | _("Expose Windows"), |
504 | _("Expose all Windows") |
505 | }, |
506 | - schemas = { |
507 | + schemas = { |
508 | Schema.WM, |
509 | Schema.WM, |
510 | Schema.WM, |
511 | |
512 | === modified file 'src/Pages/Shortcuts/section_switcher.vala' |
513 | --- src/Pages/Shortcuts/section_switcher.vala 2014-01-06 17:12:27 +0000 |
514 | +++ src/Pages/Shortcuts/section_switcher.vala 2014-03-30 21:21:15 +0000 |
515 | @@ -12,8 +12,11 @@ |
516 | |
517 | Gtk.TreeIter iter; |
518 | |
519 | - // add the sections |
520 | - for (int id = 0; id < SectionID.COUNT; id++) { |
521 | + var max_section_id = CustomShortcutSettings.available |
522 | + ? SectionID.COUNT |
523 | + : SectionID.CUSTOM; |
524 | + |
525 | + for (int id = 0; id < max_section_id; id++) { |
526 | store.append (out iter); |
527 | store.set (iter, 0, section_names[id]); |
528 | } |
529 | @@ -39,6 +42,6 @@ |
530 | }); |
531 | } |
532 | |
533 | - public signal void changed (int i); |
534 | + public signal bool changed (int i); |
535 | } |
536 | } |
537 | \ No newline at end of file |
538 | |
539 | === modified file 'src/Pages/Shortcuts/settings.vala' |
540 | --- src/Pages/Shortcuts/settings.vala 2014-01-06 17:12:27 +0000 |
541 | +++ src/Pages/Shortcuts/settings.vala 2014-03-30 21:21:15 +0000 |
542 | @@ -26,7 +26,7 @@ |
543 | var schema = schema_source.lookup (name, true); |
544 | |
545 | if (schema == null) { |
546 | - warning ("Schema \"%s\" is not installed on you system.", name); |
547 | + warning ("Schema \"%s\" is not installed on your system.", name); |
548 | schemas += (GLib.Settings) null; |
549 | } else { |
550 | schemas += new GLib.Settings.full (schema, null, null); |
551 | |
552 | === modified file 'src/Pages/Shortcuts/shortcut.vala' |
553 | --- src/Pages/Shortcuts/shortcut.vala 2014-01-06 17:12:27 +0000 |
554 | +++ src/Pages/Shortcuts/shortcut.vala 2014-03-30 21:21:15 +0000 |
555 | @@ -10,7 +10,7 @@ |
556 | string SEPARATOR = " · "; |
557 | |
558 | // constructors |
559 | - public Shortcut ( uint key, Gdk.ModifierType mod ) |
560 | + public Shortcut (uint key = 0, Gdk.ModifierType mod = (Gdk.ModifierType) 0) |
561 | { |
562 | accel_key = key; |
563 | modifiers = mod; |
564 | @@ -107,4 +107,4 @@ |
565 | } |
566 | |
567 | } |
568 | -} |
569 | \ No newline at end of file |
570 | +} |
571 | |
572 | === modified file 'src/Pages/Shortcuts/tree.vala' |
573 | --- src/Pages/Shortcuts/tree.vala 2014-01-06 17:12:27 +0000 |
574 | +++ src/Pages/Shortcuts/tree.vala 2014-03-30 21:21:15 +0000 |
575 | @@ -1,182 +1,145 @@ |
576 | -namespace Pantheon.Keyboard.Shortcuts |
577 | -{ |
578 | - // contains the shortcuts and handels all changes in gsettings |
579 | - private class Tree : Gtk.TreeView |
580 | - { |
581 | - private string[] actions; |
582 | - private Schema[] schemas; |
583 | - private string[] keys; |
584 | - |
585 | - // quick access to one item in the tree view |
586 | - public bool get_item (uint i, out string action, out Schema schema, out string key) |
587 | - { |
588 | - action = null; |
589 | - schema = (Schema) null; |
590 | - key = null; |
591 | - |
592 | - if (i < actions.length) |
593 | - { |
594 | - action = actions[i]; |
595 | - schema = schemas[i]; |
596 | - key = keys[i]; |
597 | - return true; |
598 | - } |
599 | - return false; |
600 | - } |
601 | - |
602 | - public Tree (SectionID group) |
603 | - { |
604 | - list.get_group (group, out actions, out schemas, out keys); |
605 | - |
606 | - // create list store |
607 | - var store = new Gtk.ListStore (4, typeof (string), |
608 | - typeof (string), |
609 | - typeof (Schema), |
610 | - typeof (string)); |
611 | - |
612 | - Gtk.TreeIter iter; |
613 | - |
614 | - for (int i = 0; i < actions.length; i++) |
615 | - { |
616 | - var shortcut = settings.get_val(schemas[i], keys[i]); |
617 | - |
618 | - // simply ignore missing keys/schemas |
619 | - if (shortcut == null) |
620 | - continue; |
621 | - |
622 | - store.append (out iter); |
623 | - store.set (iter, 0, actions[i], |
624 | - 1, shortcut.to_readable(), |
625 | - 2, schemas[i], // hidden |
626 | - 3, keys[i], -1); // hidden |
627 | - } |
628 | - |
629 | - // create tree view |
630 | - var cell_desc = new Gtk.CellRendererText (); |
631 | - var cell_edit = new Gtk.CellRendererAccel (); |
632 | - |
633 | - cell_edit.editable = true; |
634 | - cell_edit.accel_mode = Gtk.CellRendererAccelMode.OTHER; |
635 | - |
636 | - this.set_model (store); |
637 | - |
638 | - this.insert_column_with_attributes (-1, null, cell_desc, "text", 0); |
639 | - this.insert_column_with_attributes (-1, null, cell_edit, "text", 1); |
640 | - // debug |
641 | - //this.insert_column_with_attributes (-1, null, cell_desc, "text", 2); |
642 | - //this.insert_column_with_attributes (-1, null, cell_edit, "text", 3); |
643 | - |
644 | - this.headers_visible = false; |
645 | - this.expand = true; |
646 | - |
647 | - this.get_column (0).expand = true; |
648 | - |
649 | - this.button_press_event.connect ((event) => |
650 | - { |
651 | - if (event.window != this.get_bin_window ()) |
652 | - return false; |
653 | - |
654 | - Gtk.TreePath path; |
655 | - |
656 | - if (this.get_path_at_pos ((int) event.x, |
657 | - (int) event.y, |
658 | - out path, null, |
659 | - null, null)) |
660 | - { |
661 | - Gtk.TreeViewColumn col = this.get_column (1); |
662 | - this.grab_focus (); |
663 | - this.set_cursor (path, col, true); |
664 | - } |
665 | - |
666 | - return true; |
667 | - } ); |
668 | - |
669 | - // signals |
670 | - cell_edit.accel_edited.connect ((path, key, mods) => |
671 | - { |
672 | - var shortcut = new Shortcut (key, mods); |
673 | - change_shortcut (path, shortcut); |
674 | - } ); |
675 | - |
676 | - cell_edit.accel_cleared.connect ((path) => |
677 | - { |
678 | - change_shortcut (path, (Shortcut) null); |
679 | - } ); |
680 | - } |
681 | - |
682 | - // change a shortcut in the list store and gsettings |
683 | - private bool change_shortcut (string path, Shortcut? shortcut) |
684 | - { |
685 | - Gtk.TreeIter iter; |
686 | - GLib.Value key, schema, name; |
687 | - |
688 | - model.get_iter (out iter, new Gtk.TreePath.from_string (path)); |
689 | - |
690 | - model.get_value (iter, 0, out name); |
691 | - model.get_value (iter, 2, out schema); |
692 | - model.get_value (iter, 3, out key); |
693 | - |
694 | - |
695 | - if (shortcut != null) |
696 | - { |
697 | - // new shortcut is old shortcut? |
698 | - if (shortcut.is_equal (settings.get_val ((Schema)schema, (string)key))) |
699 | - return true; |
700 | - |
701 | - string conflict_accel; |
702 | - int conflict_group; |
703 | - int conflict_path; |
704 | - |
705 | - // check if shortcut is already used |
706 | - if (list.conflicts (shortcut, out conflict_accel, out conflict_group, out conflict_path)) |
707 | - { |
708 | - string conflict_action; |
709 | - Schema conflict_schema; |
710 | - string conflict_key; |
711 | - |
712 | - // get some info about the conflicting item |
713 | - trees[conflict_group].get_item (conflict_path, out conflict_action, out conflict_schema, out conflict_key); |
714 | - |
715 | - // ask user what to do |
716 | - var msg = new Gtk.MessageDialog (null, Gtk.DialogFlags.MODAL, |
717 | - Gtk.MessageType.WARNING, |
718 | - Gtk.ButtonsType.NONE, |
719 | - "\"%s\" is already used for \"%s\"!", shortcut.to_readable (), conflict_action); |
720 | - |
721 | - msg.secondary_text = _("If you reassign the shortcut to \"%s\", \"%s\" will be disabled").printf ((string)name, conflict_action); |
722 | - msg.add_button (_("Cancel"), 0); |
723 | - msg.add_button (_("Reassign"), 1); |
724 | - |
725 | - msg.response.connect ((response_id) => |
726 | - { |
727 | - if (response_id == 1) |
728 | - { |
729 | - trees[conflict_group].change_shortcut (conflict_path.to_string (), (Shortcut) null); |
730 | - change_shortcut (path, shortcut); |
731 | - } |
732 | - |
733 | - msg.destroy(); |
734 | - }); |
735 | - msg.show (); |
736 | - |
737 | - return false; |
738 | - } |
739 | - |
740 | - if (!shortcut.valid ()) |
741 | - return false; |
742 | - } |
743 | - |
744 | - // unset/disable shortcut |
745 | - if (shortcut == null) |
746 | - { |
747 | - (model as Gtk.ListStore).set (iter, 1, _("Disabled")); |
748 | - settings.set_val((Schema)schema, (string)key, new Shortcut(0, (Gdk.ModifierType)0)); |
749 | - return true; |
750 | - } |
751 | - |
752 | - (model as Gtk.ListStore).set (iter, 1, shortcut.to_readable ()); |
753 | - settings.set_val((Schema)schema, (string)key, shortcut); |
754 | - return true; |
755 | - } |
756 | - } |
757 | +namespace Pantheon.Keyboard.Shortcuts { |
758 | + |
759 | + private class Tree : Gtk.TreeView, DisplayTree { |
760 | + |
761 | + public SectionID group { private get; construct; } |
762 | + |
763 | + private string[] actions; |
764 | + private Schema[] schemas; |
765 | + private string[] keys; |
766 | + |
767 | + public Tree (SectionID group) { |
768 | + Object (group: group); |
769 | + |
770 | + load_and_display_shortcuts (); |
771 | + |
772 | + var cell_desc = new Gtk.CellRendererText (); |
773 | + var cell_edit = new Gtk.CellRendererAccel (); |
774 | + |
775 | + cell_edit.editable = true; |
776 | + cell_edit.accel_mode = Gtk.CellRendererAccelMode.OTHER; |
777 | + |
778 | + this.insert_column_with_attributes (-1, null, cell_desc, "text", 0); |
779 | + this.insert_column_with_attributes (-1, null, cell_edit, "text", 1); |
780 | + //this.insert_column_with_attributes (-1, null, cell_desc, "text", 2); |
781 | + //this.insert_column_with_attributes (-1, null, cell_edit, "text", 3); |
782 | + |
783 | + this.headers_visible = false; |
784 | + this.expand = true; |
785 | + |
786 | + this.get_column (0).expand = true; |
787 | + |
788 | + this.button_press_event.connect ((event) => { |
789 | + if (event.window != this.get_bin_window ()) |
790 | + return false; |
791 | + |
792 | + Gtk.TreePath path; |
793 | + |
794 | + if (this.get_path_at_pos ((int) event.x, (int) event.y, |
795 | + out path, null, null, null)) { |
796 | + Gtk.TreeViewColumn col = this.get_column (1); |
797 | + this.grab_focus (); |
798 | + this.set_cursor (path, col, true); |
799 | + } |
800 | + |
801 | + return true; |
802 | + }); |
803 | + |
804 | + cell_edit.accel_edited.connect ((path, key, mods) => { |
805 | + var shortcut = new Shortcut (key, mods); |
806 | + change_shortcut (path, shortcut); |
807 | + }); |
808 | + |
809 | + cell_edit.accel_cleared.connect ((path) => { |
810 | + change_shortcut (path, (Shortcut) null); |
811 | + }); |
812 | + } |
813 | + |
814 | + void load_and_display_shortcuts () { |
815 | + list.get_group (group, out actions, out schemas, out keys); |
816 | + |
817 | + var store = new Gtk.ListStore (4, typeof (string), typeof (string), |
818 | + typeof (Schema), typeof (string)); |
819 | + |
820 | + Gtk.TreeIter iter; |
821 | + |
822 | + for (int i = 0; i < actions.length; i++) { |
823 | + var shortcut = settings.get_val(schemas[i], keys[i]); |
824 | + |
825 | + if (shortcut == null) |
826 | + continue; |
827 | + |
828 | + store.append (out iter); |
829 | + store.set (iter, 0, actions[i], |
830 | + 1, shortcut.to_readable(), |
831 | + 2, schemas[i], // hidden |
832 | + 3, keys[i], -1); // hidden |
833 | + } |
834 | + |
835 | + model = store; |
836 | + } |
837 | + |
838 | + public bool shortcut_conflicts (Shortcut shortcut, out string name) { |
839 | + string[] actions, keys; |
840 | + Schema[] schemas; |
841 | + |
842 | + list.get_group (group, out actions, out schemas, out keys); |
843 | + |
844 | + for (int i = 0; i < actions.length; i++) { |
845 | + if (shortcut.is_equal (settings.get_val (schemas[i], keys[i]))) { |
846 | + name = actions[i]; |
847 | + return true; |
848 | + } |
849 | + } |
850 | + |
851 | + return false; |
852 | + } |
853 | + |
854 | + public void reset_shortcut (Shortcut shortcut) { |
855 | + string[] actions, keys; |
856 | + Schema[] schemas; |
857 | + var empty_shortcut = new Shortcut (); |
858 | + |
859 | + list.get_group (group, out actions, out schemas, out keys); |
860 | + |
861 | + for (int i = 0; i < actions.length; i++) |
862 | + if (shortcut.is_equal (settings.get_val (schemas[i], keys[i]))) |
863 | + settings.set_val (schemas[i], keys[i], empty_shortcut); |
864 | + |
865 | + load_and_display_shortcuts (); |
866 | + } |
867 | + |
868 | + public bool change_shortcut (string path, Shortcut? shortcut) { |
869 | + Gtk.TreeIter iter; |
870 | + GLib.Value key, schema, name; |
871 | + |
872 | + model.get_iter (out iter, new Gtk.TreePath.from_string (path)); |
873 | + |
874 | + model.get_value (iter, 0, out name); |
875 | + model.get_value (iter, 2, out schema); |
876 | + model.get_value (iter, 3, out key); |
877 | + |
878 | + string conflict_name; |
879 | + |
880 | + if (shortcut != null) { |
881 | + foreach (var tree in trees) { |
882 | + if (tree.shortcut_conflicts (shortcut, out conflict_name) == false) |
883 | + continue; |
884 | + |
885 | + var dialog = new ConflictDialog (shortcut.to_readable (), conflict_name, (string) name); |
886 | + dialog.reassign.connect (() => { |
887 | + tree.reset_shortcut (shortcut); |
888 | + settings.set_val ((Schema) schema, (string) key, shortcut); |
889 | + load_and_display_shortcuts (); |
890 | + }); |
891 | + dialog.show (); |
892 | + return false; |
893 | + } |
894 | + } |
895 | + |
896 | + settings.set_val ((Schema) schema, (string) key, shortcut ?? new Shortcut ()); |
897 | + load_and_display_shortcuts (); |
898 | + return true; |
899 | + } |
900 | + } |
901 | } |
902 | \ No newline at end of file |
903 | |
904 | === modified file 'src/Pages/shortcuts.vala' |
905 | --- src/Pages/shortcuts.vala 2014-01-06 17:12:27 +0000 |
906 | +++ src/Pages/shortcuts.vala 2014-03-30 21:21:15 +0000 |
907 | @@ -5,9 +5,18 @@ |
908 | // class to interact with gsettings |
909 | private Shortcuts.Settings settings; |
910 | // array of tree views, one for each section |
911 | - private Tree[] trees; |
912 | + private DisplayTree[] trees; |
913 | |
914 | - private enum SectionID { WINDOWS, WORKSPACES, SCREENSHOTS, APPS, MEDIA, A11Y, COUNT } |
915 | + private enum SectionID { |
916 | + WINDOWS, |
917 | + WORKSPACES, |
918 | + SCREENSHOTS, |
919 | + APPS, |
920 | + MEDIA, |
921 | + A11Y, |
922 | + CUSTOM, |
923 | + COUNT |
924 | + } |
925 | |
926 | private string[] section_names; |
927 | |
928 | @@ -27,6 +36,8 @@ |
929 | |
930 | public Page () |
931 | { |
932 | + CustomShortcutSettings.init (); |
933 | + |
934 | // init public elements |
935 | section_names = { |
936 | _("Windows"), |
937 | @@ -34,15 +45,18 @@ |
938 | _("Screenshots"), |
939 | _("Applications"), |
940 | _("Media"), |
941 | - _("Universal Access") |
942 | + _("Universal Access"), |
943 | + _("Custom") |
944 | }; |
945 | |
946 | list = new List (); |
947 | settings = new Shortcuts.Settings (); |
948 | |
949 | - for (int id = 0; id < SectionID.COUNT; id++) { |
950 | + for (int id = 0; id < SectionID.CUSTOM; id++) |
951 | trees += new Tree ((SectionID) id); |
952 | - } |
953 | + |
954 | + if (CustomShortcutSettings.available) |
955 | + trees += new CustomTree (); |
956 | |
957 | // private elements |
958 | var shortcut_display = new ShortcutDisplay (trees); |
959 | @@ -51,9 +65,7 @@ |
960 | this.attach (section_switcher, 0, 0, 1, 1); |
961 | this.attach (shortcut_display, 1, 0, 2, 1); |
962 | |
963 | - section_switcher.changed.connect ((i) => { |
964 | - shortcut_display.change_selection (i); |
965 | - }); |
966 | + section_switcher.changed.connect (shortcut_display.change_selection); |
967 | } |
968 | } |
969 | -} |
970 | \ No newline at end of file |
971 | +} |
Code style wise this can't really pass for now. You added a new file that is tab-indented (conflict_ dialog. vala). (and I realize you did it to keep consistency with existing files in the project, but new code should *usually* be good code).
Also diff lines 727-735 you mixed tabs and spaces.
I can't yet review the code itself, give me a couple of days. I'll test it in the meanwhile too.