engine: add support for WritabilityNotify
[dconf.git] / editor / dconf-editor.vala
blob671b9b55f8b4daa0a0af380d75f0d82431bb5ba7
1 class ConfigurationEditor : Gtk.Application
3 private SettingsModel model;
5 private Settings settings;
6 private Gtk.Builder ui;
7 private Gtk.ApplicationWindow window;
8 private int window_width = 0;
9 private int window_height = 0;
10 private bool window_is_maximized = false;
11 private bool window_is_fullscreen = false;
12 private Gtk.TreeView dir_tree_view;
13 private Gtk.TreeView key_tree_view;
14 private Gtk.Grid key_info_grid;
15 private Gtk.Label schema_label;
16 private Gtk.Label summary_label;
17 private Gtk.Label description_label;
18 private Gtk.Label type_label;
19 private Gtk.Label default_label;
20 private Gtk.Action set_default_action;
21 private Gtk.Box search_box;
22 private Gtk.Entry search_entry;
23 private Gtk.Label search_label;
25 private Key? selected_key;
27 private const GLib.ActionEntry[] action_entries =
29 { "find", find_cb },
30 { "about", about_cb },
31 { "quit", quit_cb }
34 public ConfigurationEditor()
36 Object(application_id: "ca.desrt.dconf-editor", flags: ApplicationFlags.FLAGS_NONE);
39 protected override void startup()
41 base.startup();
43 Environment.set_application_name (_("dconf Editor"));
45 add_action_entries (action_entries, this);
47 settings = new Settings ("ca.desrt.dconf-editor.Settings");
49 model = new SettingsModel();
51 ui = new Gtk.Builder();
52 try
54 ui.add_from_resource("/ca/desrt/dconf-editor/dconf-editor.ui");
56 catch (Error e)
58 error("Failed to load UI: %s", e.message);
60 window = new Gtk.ApplicationWindow(this);
61 window.set_default_size(600, 300);
62 window.title = _("dconf Editor");
63 window.window_state_event.connect(main_window_window_state_event_cb);
64 window.configure_event.connect(main_window_configure_event_cb);
65 window.add(ui.get_object("box1") as Gtk.Box);
67 var menu_ui = new Gtk.Builder();
68 try
70 menu_ui.add_from_resource("/ca/desrt/dconf-editor/dconf-editor-menu.ui");
72 catch (Error e)
74 error("Failed to load menu UI: %s", e.message);
76 set_app_menu((MenuModel)menu_ui.get_object("menu"));
78 window.set_default_size (settings.get_int ("window-width"), settings.get_int ("window-height"));
79 if (settings.get_boolean ("window-is-fullscreen"))
80 window.fullscreen ();
81 else if (settings.get_boolean ("window-is-maximized"))
82 window.maximize ();
84 dir_tree_view = new DConfDirView();
85 dir_tree_view.set_model(model);
86 dir_tree_view.get_selection().changed.connect(dir_selected_cb); // FIXME: Put in view
87 dir_tree_view.show();
88 var scroll = ui.get_object("directory_scrolledwindow") as Gtk.ScrolledWindow;
89 scroll.add(dir_tree_view);
91 key_tree_view = new DConfKeyView();
92 key_tree_view.show();
93 key_tree_view.get_selection().changed.connect(key_selected_cb);
94 scroll = ui.get_object("key_scrolledwindow") as Gtk.ScrolledWindow;
95 scroll.add(key_tree_view);
97 key_info_grid = ui.get_object("key_info_grid") as Gtk.Grid;
98 schema_label = ui.get_object("schema_label") as Gtk.Label;
99 summary_label = ui.get_object("summary_label") as Gtk.Label;
100 description_label = ui.get_object("description_label") as Gtk.Label;
101 type_label = ui.get_object("type_label") as Gtk.Label;
102 default_label = ui.get_object("default_label") as Gtk.Label;
103 set_default_action = ui.get_object("set_default_action") as Gtk.Action;
104 set_default_action.activate.connect(set_default_cb);
106 search_box = ui.get_object("search_box") as Gtk.Box;
107 search_box.key_press_event.connect ((event) =>
109 if (event.keyval == Gdk.Key.Escape)
111 search_box.hide();
112 return true;
114 return false;
116 search_entry = ui.get_object("search_entry") as Gtk.Entry;
117 search_label = ui.get_object("search_label") as Gtk.Label;
118 search_entry.activate.connect(find_next_cb);
119 var search_box_close_button = ui.get_object("search_box_close_button") as Gtk.Button;
120 search_box_close_button.clicked.connect(() =>
122 search_box.hide();
125 var search_next_button = ui.get_object("search_next_button") as Gtk.Button;
126 search_next_button.clicked.connect(find_next_cb);
128 /* Always select something */
129 Gtk.TreeIter iter;
130 if (model.get_iter_first(out iter))
131 dir_tree_view.get_selection().select_iter(iter);
134 protected override void activate()
136 window.present();
139 protected override void shutdown ()
141 base.shutdown();
142 settings.set_int ("window-width", window_width);
143 settings.set_int ("window-height", window_height);
144 settings.set_boolean ("window-is-maximized", window_is_maximized);
145 settings.set_boolean ("window-is-fullscreen", window_is_fullscreen);
148 private void dir_selected_cb()
150 KeyModel? key_model = null;
152 Gtk.TreeIter iter;
153 if (dir_tree_view.get_selection().get_selected(null, out iter))
154 key_model = model.get_directory(iter).key_model;
156 key_tree_view.set_model(key_model);
158 /* Always select something */
159 if (key_model != null && key_model.get_iter_first(out iter))
160 key_tree_view.get_selection().select_iter(iter);
163 private string key_to_description(Key key)
165 switch(key.schema.type)
167 case "y":
168 case "n":
169 case "q":
170 case "i":
171 case "u":
172 case "x":
173 case "t":
174 case "d":
175 Variant min, max;
176 if (key.schema.range != null)
178 min = key.schema.range.min;
179 max = key.schema.range.max;
181 else
183 min = key.get_min();
184 max = key.get_max();
186 return _("Integer [%s..%s]").printf(min.print(false), max.print(false));
187 case "b":
188 return _("Boolean");
189 case "s":
190 return _("String");
191 case "<enum>":
192 return _("Enumeration");
193 default:
194 return key.schema.type;
198 private void key_selected_cb()
200 if(selected_key != null)
201 selected_key.value_changed.disconnect(key_changed_cb);
203 Gtk.TreeIter iter;
204 Gtk.TreeModel model;
205 if (key_tree_view.get_selection().get_selected(out model, out iter))
207 var key_model = (KeyModel) model;
208 selected_key = key_model.get_key(iter);
210 else
211 selected_key = null;
213 if(selected_key != null)
214 selected_key.value_changed.connect(key_changed_cb);
216 key_info_grid.sensitive = selected_key != null;
217 set_default_action.sensitive = selected_key != null && !selected_key.is_default;
219 string schema_name = "", summary = "", description = "", type = "", default_value = "";
221 if (selected_key != null)
223 if (selected_key.schema != null)
225 var gettext_domain = selected_key.schema.gettext_domain;
226 schema_name = selected_key.schema.schema.id;
227 if (selected_key.schema.summary != null)
228 summary = selected_key.schema.summary;
229 if (gettext_domain != null && summary != "")
230 summary = dgettext(gettext_domain, summary);
231 if (selected_key.schema.description != null)
232 description = selected_key.schema.description;
233 if (gettext_domain != null && description != "")
234 description = dgettext(gettext_domain, description);
235 type = key_to_description(selected_key);
236 default_value = selected_key.schema.default_value.print(false);
238 else
240 schema_name = _("No schema");
244 schema_label.set_text(schema_name);
245 summary_label.set_text(summary.strip());
246 description_label.set_text(description.strip());
247 type_label.set_text(type);
248 default_label.set_text(default_value);
251 private void key_changed_cb(Key key)
253 set_default_action.sensitive = selected_key != null && !selected_key.is_default;
256 private void set_default_cb (Gtk.Action action)
258 if (selected_key == null)
259 return;
260 selected_key.set_to_default();
263 private bool main_window_configure_event_cb (Gtk.Widget widget, Gdk.EventConfigure event)
265 if (!window_is_maximized && !window_is_fullscreen)
267 window_width = event.width;
268 window_height = event.height;
271 return false;
274 private bool main_window_window_state_event_cb (Gtk.Widget widget, Gdk.EventWindowState event)
276 if ((event.changed_mask & Gdk.WindowState.MAXIMIZED) != 0)
277 window_is_maximized = (event.new_window_state & Gdk.WindowState.MAXIMIZED) != 0;
278 if ((event.changed_mask & Gdk.WindowState.FULLSCREEN) != 0)
279 window_is_fullscreen = (event.new_window_state & Gdk.WindowState.FULLSCREEN) != 0;
281 return false;
284 private void find_cb()
286 search_box.show();
287 search_entry.grab_focus();
290 private void find_next_cb()
292 search_label.set_text("");
294 /* Get the current position in the tree */
295 Gtk.TreeIter iter;
296 var key_iter = Gtk.TreeIter();
297 var have_key_iter = false;
298 if (dir_tree_view.get_selection().get_selected(null, out iter))
300 if (key_tree_view.get_selection().get_selected(null, out key_iter))
302 var dir = model.get_directory(iter);
303 if (dir.key_model.iter_next(ref key_iter))
304 have_key_iter = true;
305 else
306 get_next_iter(ref iter);
309 else if (!model.get_iter_first(out iter))
310 return;
312 var on_first_directory = true;
315 /* Select next directory that matches */
316 var dir = model.get_directory(iter);
317 if (!have_key_iter)
319 have_key_iter = dir.key_model.get_iter_first(out key_iter);
320 if (!on_first_directory && dir.name.index_of(search_entry.text) >= 0)
322 dir_tree_view.expand_to_path(model.get_path(iter));
323 dir_tree_view.get_selection().select_iter(iter);
324 dir_tree_view.scroll_to_cell(model.get_path(iter), null, false, 0, 0);
325 return;
328 on_first_directory = false;
330 /* Select next key that matches */
331 if (have_key_iter)
335 var key = dir.key_model.get_key(key_iter);
336 if (key_matches(key, search_entry.text))
338 dir_tree_view.expand_to_path(model.get_path(iter));
339 dir_tree_view.get_selection().select_iter(iter);
340 dir_tree_view.scroll_to_cell(model.get_path(iter), null, false, 0, 0);
341 key_tree_view.get_selection().select_iter(key_iter);
342 key_tree_view.scroll_to_cell(dir.key_model.get_path(key_iter), null, false, 0, 0);
343 return;
345 } while(dir.key_model.iter_next(ref key_iter));
347 have_key_iter = false;
348 } while(get_next_iter(ref iter));
350 search_label.set_text(_("Not found"));
353 private bool key_matches (Key key, string text)
355 /* Check key name */
356 if (key.name.index_of(text) >= 0)
357 return true;
359 /* Check key schema (description) */
360 if (key.schema != null)
362 if (key.schema.summary != null && key.schema.summary.index_of(text) >= 0)
363 return true;
364 if (key.schema.description != null && key.schema.description.index_of(text) >= 0)
365 return true;
368 /* Check key value */
369 if (key.value.is_of_type(VariantType.STRING) && key.value.get_string().index_of(text) >= 0)
370 return true;
372 return false;
375 private bool get_next_iter(ref Gtk.TreeIter iter)
377 /* Search children next */
378 if (model.iter_has_child(iter))
380 model.iter_nth_child(out iter, iter, 0);
381 return true;
384 /* Move to the next branch */
385 while (!model.iter_next(ref iter))
387 /* Otherwise move to the parent and onto the next iter */
388 if (!model.iter_parent(out iter, iter))
389 return false;
392 return true;
395 private void about_cb()
397 string[] authors = { "Robert Ancell", null };
398 string license = _("This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA");
399 Gtk.show_about_dialog (window,
400 "program-name", _("dconf Editor"),
401 "version", Config.VERSION,
402 "comments",
403 _("Directly edit your entire configuration database"),
404 "copyright", _("Copyright \xc2\xa9 Canonical Ltd"),
405 "license", license,
406 "wrap-license", true,
407 "authors", authors,
408 "translator-credits", _("translator-credits"),
409 "logo-icon-name", "dconf-editor",
410 null);
413 private void quit_cb()
415 window.destroy();
418 public static int main(string[] args)
420 Intl.setlocale (LocaleCategory.ALL, "");
421 Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
422 Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
423 Intl.textdomain (Config.GETTEXT_PACKAGE);
425 var app = new ConfigurationEditor();
426 return app.run(args);