NeoLayoutViewer/src/config-manager.vala

207 lines
6.7 KiB
Vala

/* vim: set tabstop=2:softtabstop=2:shiftwidth=2:noexpandtab */
// modules: Gtk
namespace NeoLayoutViewer {
public class ConfigManager {
public Gee.Map<string, string> config;
private Gee.Map<string, string> description; // allow optional commenting config entrys.
public string used_config_path;
public ConfigManager(string[] paths, string conffile) {
this.config = new Gee.TreeMap<string, string>();
this.description = new Gee.TreeMap<string, string>();
//add default values, if key not set in the config file
add_defaults();
//try to read/create config file on given array of paths
string conffile2 = null;
//1. Try to read conf file
foreach( var path in paths ){
string testfile = @"$(path)/$(conffile)";
debug(@"Search $(testfile)\n");
if( search_config_file(testfile) ){
conffile2 = testfile;
debug(@"Found $(testfile)\n");
break;
}
}
//2. Try deprecated name with leading dot
if( conffile2 == null ){
foreach( var path in paths ){
string testfile = @"$(path)/.$(conffile)";
debug(@"Search $(testfile)\n");
if( search_config_file(testfile) ){
conffile2 = testfile;
debug(@"Found $(testfile)\n");
break;
}
}
}
//3. Try to write new conf file if read had failed
if( conffile2 == null ){
foreach( var path in paths ){
string testfile = @"$(path)/$(conffile)";
if( create_conf_file(testfile) > -1){
debug(@"Create $(testfile)\n");
conffile2 = testfile;
break;
}
}
}
debug(@"Config file: $(conffile2)");
if(search_config_file(conffile2))
load_config_file(conffile2);
add_intern_values();
used_config_path = conffile2;
}
public Gee.Map<string, string> getConfig() {
return config;
}
private void addSetting(string name, string val, string? comment) {
config.set(name, val);
if (comment != null) {
description.set(name, comment);
}
}
/*
Standard values. This vaules will be written in the config file
if it was not found.
*/
public void add_defaults(){
//config.set("show_shortcut", "<Mod4><Super_L>n", "Toggle the visibility of the window.");
addSetting("show_shortcut", "<Ctrl><Alt>q", "Toggle the visibility of the window.");
addSetting("on_top", "1", "Show window on top.");
addSetting("position", "3", "Window position on startup (num pad orientation)\n"
+ "# Add 10 to start on second monitor, etc.");
/* width of application window
if value between 'resolution width'*max_width and 'resolution width'*min_width */
addSetting("width", "1000", "Width in Pixel. Min_width and max_width bound sensible values. ");
addSetting("min_width", "0.25", "Minimal width. 1=full screen width");
addSetting("max_width", "0.5", "Maximal width. 1=full screen width");
addSetting("monitor_shortcut", "<Ctrl><Alt><Shift>n", "Circle window through monitors.\n"
+ "# Use same value as 'show_shortcut' to combine both functionalities.");
addSetting("move_shortcut", "<Ctrl><Alt>n", "Circle through window positions.");
addSetting("position_cycle", "2 3 6 1 3 9 4 7 8 | 12 13 16 11 13 19 14 17 18 |",
"""List of positions (num pad orientation)
# The number on the n-th index marks the next position of the window.
# Default cycle: 7 8 9
#
# 4 5 6
#
# 1 2 3
#
# position_cycle = 2 3 6 1 3 9 4 7 8 | 12 13 16 11 13 19 14 17 18 |
#
# Further examples:
# monitor 1 2
# position 1 2 3 4 5 6 7 8 9 | 11 12 13 14 15 18 17 18 19 |
# position_cycle = 3 3 9 1 3 9 1 7 7 | 13 13 19 11 13 19 11 17 17 | (corners only)
# position_cycle =3 3 11 1 3 9 1 7 7 | 13 13 19 11 13 19 9 17 17 | (cycle over two monitors)""");
addSetting("display_numpad", "1", null);
addSetting("display_function_keys", "0", null);
addSetting("window_selectable", "0", "Disable window selection to use the program as virtual keyboard.");
addSetting("window_decoration", "0", "Show window decoration/border (not recommended).");
addSetting("screen_width", "auto", "Set the resolution of your screen manually, if the automatic detection fails.");
addSetting("screen_height", "auto", "Set the resolution of your screen manually, if the automatic detection fails.");
addSetting("show_on_startup", "1", "Show window on startup.");
addSetting("asset_folder", "./assets", "Default lookup folder image data.");
addSetting("color_event_boxes", "0", "(Debugging) Show event boxes of virtual keyboard.");
}
/*
Enrich setting map by some values. User can not change them because
intern values overrides external values.
*/
private void add_intern_values() {
config.set("numpad_width", "350");
config.set("function_keys_height", "30");
}
private bool search_config_file(string conffile) {
var file = File.new_for_path(conffile);
return file.query_exists(null);
}
private int create_conf_file(string conffile) {
var file = File.new_for_path(conffile);
try {
//Create a new file with this name
var file_stream = file.create(FileCreateFlags.NONE);
// Test for the existence of file
if (!file.query_exists()) {
GLib.stdout.printf("Can't create config file.\n");
return -1;
}
// Write text data to file
var data_stream = new DataOutputStream(file_stream);
foreach (Gee.Map.Entry<string, string> e in this.config.entries) {
if (this.description.has_key(e.key)) {
data_stream.put_string("# " + this.description.get(e.key) + "\n");
}
data_stream.put_string(e.key + " = " + e.value + "\n");
}
} // Streams
catch ( GLib.IOError e){ return -1; }
catch ( GLib.Error e){ return -1; }
return 0;
}
private int load_config_file(string conffile) {
// A reference to our file
var file = File.new_for_path(conffile);
try {
// Open file for reading and wrap returned FileInputStream into a
// DataInputStream, so we can read line by line
var in_stream = new DataInputStream(file.read(null));
string line;
string[] split;
var comment = new Regex("^#.*$");
var regex = new Regex("(#[^=]*)*[ ]*=[ ]*");
// Read lines until end of file (null) is reached
while ((line = in_stream.read_line(null, null)) != null) {
if (comment.match(line)) continue;
split = regex.split(line);
if(split.length>1){
this.config.set(split[0].strip(), split[1].strip());
}
}
} catch (GLib.IOError e) {
error ("%s", e.message);
} catch (RegexError e) {
error ("%s", e.message);
} catch (GLib.Error e) {
error ("%s", e.message);
}
return 0;
}
} // end ConfigManager
} // end namespace