Merge pull request #2566 from keymanapp/linux-options-dconf

feat(linux): Keyboard options configuration dialog
This commit is contained in:
Darcy Wong 2020-02-05 15:26:10 +07:00 • committed by GitHub
commit 8f73f5ec6c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 528 additions and 37 deletions

7
linux/.editorconfig Normal file
View file

@ -0,0 +1,7 @@
root = true
[*.py]
trim_trailing_whitespace = true
intent_stype = space
intent_size = 4

View file

@ -13,6 +13,9 @@
* Work on Linux packaging (#2263, #2290, #2320, #2321, #2325, #2474, #2515, #2551)
## 2019-09-19 12.0.18 beta
* New Feature:
* Add ability to set keyboard options from options.htm dialog (#2566)
* Bug Fix:
* Extract icon from kmx instead of downloading it (#2075)

View file

@ -3,7 +3,7 @@
/*
* Keyman Input Method for IBUS (The Input Bus)
*
* Copyright (C) 2009-2018 SIL International
* Copyright (C) 2009-2020 SIL International
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
@ -26,6 +26,7 @@
#include <stdio.h>
#include <gdk/gdk.h>
#include <gio/gio.h>
#include <keyman/keyboardprocessor.h>
#include "keymanutil.h"
@ -325,7 +326,14 @@ ibus_keyman_engine_constructor (GType type,
}
g_free(kmx_file);
km_kbp_option_item *keyboard_opts = g_new0(km_kbp_option_item, 4);
// Retrieve keyboard options from DConf
// TODO: May need unique packageID and keyboard ID
g_message("Loading options for kb_name: %s", keyman->kb_name);
GQueue *queue_options = keyman_get_options_queue_fromdconf(keyman->kb_name, keyman->kb_name);
int num_options = g_queue_get_length(queue_options);
// Allocate enough options for: 3 environments plus num_options plus 1 pad struct of 0's
km_kbp_option_item *keyboard_opts = g_new0(km_kbp_option_item, KEYMAN_ENVIRONMENT_OPTIONS + num_options + 1);
keyboard_opts[0].scope = KM_KBP_OPT_ENVIRONMENT;
km_kbp_cp *cp = g_utf8_to_utf16 ("platform", -1, NULL, NULL, NULL);
@ -371,7 +379,13 @@ ibus_keyman_engine_constructor (GType type,
// g_free(lang);
keyboard_opts[2].value = cp;
// keyboard_opts[3] already initialised to {0, 0, 0}
// If queue_options contains keyboard options, pop them into keyboard_opts[3] onward
for(int i=0; i<num_options; i++)
{
memmove(&(keyboard_opts[KEYMAN_ENVIRONMENT_OPTIONS+i]), g_queue_pop_head(queue_options), sizeof(km_kbp_option_item));
}
// keyboard_opts[tail] already initialised to {0, 0, 0}
km_kbp_status status_keyboard = km_kbp_keyboard_load(abs_kmx_path, &(keyman->keyboard));
g_free(abs_kmx_path);
@ -388,10 +402,11 @@ ibus_keyman_engine_constructor (GType type,
{
g_warning("problem creating km_kbp_state");
}
for (int i =0; i < 3; i++) {
for (int i=0; i < KEYMAN_ENVIRONMENT_OPTIONS + num_options + 1; i++) {
g_free((km_kbp_cp *)keyboard_opts[i].key);
g_free((km_kbp_cp *)keyboard_opts[i].value);
}
g_queue_free_full(queue_options, NULL);
g_free(keyboard_opts);
reset_context(engine);
@ -793,6 +808,29 @@ ibus_keyman_engine_process_key_event (IBusEngine *engine,
break;
case KM_KBP_IT_PERSIST_OPT:
g_message("PERSIST_OPT action %d/%d", i+1, (int)num_action_items);
// Save keyboard option
if (action_items[i].option != NULL)
{
// Allocate for 1 option plus 1 pad struct of 0's
km_kbp_option_item *keyboard_opts = g_new0(km_kbp_option_item, 2);
memmove(&(keyboard_opts[0]), action_items[i].option, sizeof(km_kbp_option_item));
event_status = km_kbp_state_options_update(keyman->state, keyboard_opts);
if (event_status != KM_KBP_STATUS_OK)
{
g_warning("problem saving option for km_kbp_keyboard");
}
g_free(keyboard_opts);
// Put the keyboard option into DConf
if (action_items[i].option != NULL && action_items[i].option->key != NULL &&
action_items[i].option->value != NULL)
{
g_message("Saving keyboard option to DConf");
// Load the current keyboard options from DConf
keyman_put_options_todconf(keyman->kb_name, keyman->kb_name,
action_items[i].option->key, action_items[i].option->value);
}
}
break;
case KM_KBP_IT_EMIT_KEYSTROKE:
if (keyman->char_buffer != NULL)
@ -976,3 +1014,4 @@ ibus_keyman_engine_property_activate (IBusEngine *engine,
parent_class->property_activate (engine, prop_name, prop_state);
}

View file

@ -55,7 +55,7 @@
#include <glib.h>
#include <glib/gprintf.h>
#include <string.h>
#include <keyman/keyboardprocessor.h>
#include "keymanutil.h"
#include "kmpdetails.h"
@ -300,6 +300,154 @@ ibus_keyman_get_component (void)
return component;
}
// Obtain Keyboard Options from DConf and parse into a GQueue of struct km_kbp_option_item
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
//
// Parameters:
// package_id (gchar *): Package ID
// keyboard_id (gchar *): Keyboard ID
//
// Returns a newly allocated gchar**; free with g_strfreev()
gchar**
keyman_get_options_fromdconf(gchar *package_id,
gchar *keyboard_id)
{
g_message("keyman_get_options_fromdconf");
// Obtain keyboard options from DConf
gchar *path = g_strdup_printf("%s%s/%s/", KEYMAN_DCONF_PATH, package_id, keyboard_id);
GSettings *child_settings = g_settings_new_with_path(KEYMAN_CHILD_DCONF_NAME, path);
gchar **options = NULL;
if (child_settings != NULL)
{
options = g_settings_get_strv(child_settings, KEYMAN_DCONF_OPTIONS_KEY);
}
g_object_unref(G_OBJECT(child_settings));
g_free(path);
return options;
}
// Obtain Keyboard Options from DConf and parse into a GQueue of struct km_kbp_option_item
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
//
// Parameters:
// package_id (gchar *): Package ID
// keyboard_id (gchar *): Keyboard ID
//
// Return a newly allocated GQueue; free with g_queue_free_full()
GQueue*
keyman_get_options_queue_fromdconf(gchar *package_id,
gchar *keyboard_id)
{
g_message("keyman_get_options_queue_fromdconf");
GQueue *queue_options = g_queue_new();
// Obtain keyboard options from DConf
gchar **options = keyman_get_options_fromdconf(package_id, keyboard_id);
// Parse options into queue_options
if (*options != NULL)
{
int index = 0;
while (options[index] != NULL)
{
gchar **option_tokens = g_strsplit(options[index], "=", 2);
if (option_tokens != NULL && option_tokens[0] != NULL && option_tokens[1] != NULL)
{
g_message("Keyboard Option [%d], %s=%s", index, option_tokens[0], option_tokens[1]);
km_kbp_option_item *opt = g_new0(km_kbp_option_item, 1);
opt[0].scope = KM_KBP_OPT_KEYBOARD;
km_kbp_cp *ocp = g_utf8_to_utf16(option_tokens[0], -1, NULL, NULL, NULL);
opt[0].key = ocp;
ocp = g_utf8_to_utf16 (option_tokens[1], -1, NULL, NULL, NULL);
opt[0].value = ocp;
g_queue_push_tail(queue_options, opt);
}
index++;
}
}
return queue_options;
}
// Write new keyboard option to DConf.
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
// If the option key already exists, the value is updated. Otherwise a new string 'option_key=option_value' is appended.
//
// Parameters:
// package_id (gchar *): Package ID
// keyboard_id (gchar *): Keyboard ID
// option_key (gchar *): Key for the new option
// option_value (gchar *): Value of the new option
void
keyman_put_options_todconf(gchar *package_id,
gchar *keyboard_id,
gchar *option_key,
gchar *option_value)
{
g_message("keyman_put_options_todconf");
if (package_id == NULL || keyboard_id == NULL || option_key == NULL || option_value == NULL)
{
return;
}
// Obtain keyboard options from DConf
gchar **options = keyman_get_options_fromdconf(package_id, keyboard_id);
gchar *needle = g_strdup_printf("%s=", option_key);
gchar *kvp = g_strdup_printf("%s=%s", option_key, option_value);
if (*options != NULL)
{
int index = 0;
gboolean option_updated = FALSE;
while (options[index] != NULL)
{
// If option_key already exists, update value with option_value
if (g_strrstr(options[index], needle) != NULL)
{
options[index] = kvp;
option_updated = TRUE;
break;
}
index++;
}
if (!option_updated)
{
// Resize to add new option and null-terminate
options = g_realloc(options, strlen(kvp) + 1);
options[index] = kvp;
options[index+1] = NULL;
}
}
else
{
// If options don't exist, allocate space for new option and null-terminate
options = g_malloc(strlen(kvp) + 1);
options[0] = kvp;
options[1] = NULL;
}
// Write to DConf
gchar *path = g_strdup_printf("%s%s/%s/", KEYMAN_DCONF_PATH, package_id, keyboard_id);
GSettings *child_settings = g_settings_new_with_path(KEYMAN_CHILD_DCONF_NAME, path);
if (child_settings != NULL)
{
g_message("writing keyboard options to DConf");
g_settings_set_strv(child_settings, KEYMAN_DCONF_OPTIONS_KEY, options);
}
g_object_unref(G_OBJECT(child_settings));
g_free(path);
g_free(kvp);
g_free(needle);
g_free(options);
}
#ifdef DEBUG
#include <locale.h>

View file

@ -3,7 +3,7 @@
/*
* Keyman Input Method for IBUS (The Input Bus)
*
* Copyright (C) 2018 SIL International
* Copyright (C) 2018, 2020 SIL International
*
* kmflutil is dual licensed under the MIT or GPL licenses as described below.
*
@ -53,9 +53,60 @@
#define __KEYMANUTIL_H__
#include <ibus.h>
#include <gmodule.h>
#include <keyman/keyboardprocessor.h>
// Number of default Keyboard processor environment options for: "platform", "baseLayout", and "baseLayoutAlt"
#define KEYMAN_ENVIRONMENT_OPTIONS 3
// Path information for Keyman keyboard options in DConf
#define KEYMAN_DCONF_NAME "com.keyman.options"
#define KEYMAN_CHILD_DCONF_NAME "com.keyman.options.child"
#define KEYMAN_DCONF_PATH "/desktop/ibus/keyman/options/"
#define KEYMAN_DCONF_OPTIONS_KEY "options"
void ibus_keyman_init (void);
GList *ibus_keyman_list_engines (void);
IBusComponent *ibus_keyman_get_component (void);
// Obtain Keyboard Options from DConf and parse into a GQueue of struct km_kbp_option_item
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
//
// Parameters:
// package_id (gchar *): Package ID
// keyboard_id (gchar *): Keyboard ID
//
// Returns a newly allocated gchar**; free with g_strfreev()
gchar** keyman_get_options_fromdconf
(gchar *package_id,
gchar *keyboard_id);
// Obtain Keyboard Options from DConf and parse into a GQueue of struct km_kbp_option_item
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
//
// Parameters:
// package_id (gchar *): Package ID
// keyboard_id (gchar *): Keyboard ID
//
// Return a newly allocated GQueue; free with g_queue_free_full()
GQueue* keyman_get_options_queue_fromdconf
(gchar *package_id,
gchar *keyboard_id);
// Write new keyboard option to DConf.
// DConf options are in a list of strings like ['option_key1=value1', 'option_key2=value2']
// If the option key already exists, the value is updated. Otherwise a new string 'option_key=option_value' is appended.
//
// Parameters:
// package_id (gchar *): Package ID
// keyboard_id (gchar *): Keyboard ID
// option_key (gchar *): Key for the new option
// option_value (gchar *): Value of the new option
void keyman_put_options_todconf
(gchar *package_id,
gchar *keyboard_id,
gchar *option_key,
gchar *option_value);
#endif

View file

@ -16,7 +16,7 @@ install-temp:
mkdir -p /tmp/kmfl/`python3 -c 'import sys;import os;pythonver="python%d.%d" % (sys.version_info[0], sys.version_info[1]);sitedir = os.path.join("lib", pythonver, "site-packages");print(sitedir)'`
PYTHONUSERBASE=/tmp/kmfl python3 setup.py install --user
uninstall: # run as sudo
uninstall: clean # run as sudo
rm -rf /usr/local/share/keyman/icons
rm -f /usr/local/share/man/man1/km-*.1
pip3 uninstall keyman_config

View file

@ -10,9 +10,16 @@ python3-requests-cache python3 python3-gi gir1.2-webkit-3.0 dconf-cli python3-se
You will also need kmflcomp either from a package or built and installed locally.
run the script `./createkeymandirs.sh` to create the directories for these programs to
Run the script `./createkeymandirs.sh` to create the directories for these programs to
install the packages to
Also copy and compile the GSettings schema
```bash
cd keyman_config
sudo cp com.keyman.gschema.xml /usr/share/glib-2.0/schemas
sudo glib-compile-schemas /usr/share/glib-2.0/schemas
```
### Installing manually from the repo
`make && sudo make install` will install locally to /usr/local
@ -32,6 +39,7 @@ This displays a configuration panel that shows the currently installed Keyman ke
* `Uninstall` - uninstall selected keyboard
* `About` - show information about selected keyboard
* `Help` - display help documentation about selected keyboard
* `Options` - display options.htm form for setting keyboard options
-----------------------------------
* `Refresh` - useful if you install or uninstall on the commandline while running km-config.
@ -43,12 +51,9 @@ This displays a configuration panel that shows the currently installed Keyman ke
This uses the keyman.com website to install kmps.
The website doesn't know about linux yet (until after 10.0 release) so
pretending to be a mac for now.
Search for a language or keyboard in the search box
Select a keyboard from the list
In 'Downloads for your device' there will be a 'Install keyboard' button for the keyboard for macOS
Search for a language or keyboard in the search box.
Select a keyboard from the list.
In 'Downloads for your device' there will be an 'Install keyboard' button for the keyboard for Linux.
Click it to download the keyboard and bring up the `InstallKmpWindow` for more details and to confirm installing.
Secondary-click gives you a menu including 'Back' to go back a page.

View file

@ -0,0 +1,15 @@
<schemalist>
<schema id="com.keyman.options" path="/desktop/ibus/keyman/options/">
<child name="keyboard-options" schema="com.keyman.options.child"/>
</schema>
<schema id="com.keyman.options.child">
<key name="options" type="as">
<default>[]</default>
<summary>keyboard options.htm settings</summary>
<description>List of strings</description>
</key>
</schema>
</schemalist>

View file

@ -0,0 +1,73 @@
#!/usr/bin/python3
import logging
from gi.repository import Gio, Gtk
# DConf path destkop/ibus/keyman/options
DCONF_BASE = "com.keyman.options"
# Utilities to get and set Keyman options in DConf:
# /desktop/ibus/keyman/options/packageID/keyboardID/options
def get_child_schema(info):
settings = Gio.Settings.new(DCONF_BASE)
path = settings.get_property('path')
if not path.endswith('/'):
path += '/'
path += info['packageID'] + '/' + info['keyboardID'] + '/'
return Gio.Settings(DCONF_BASE + '.child', path)
def get_option(info):
"""
Get the Keyman keyboard options from DConf
Convert from list of comma-separated strings into dictionary
Args:
info: dictionary
packageID (str): Package ID
keyboardID(str): Keyboard ID
Returns:
result (dictionary): Keyboard options
"""
result = {}
if "packageID" in info and "keyboardID" in info:
child_schema = get_child_schema(info)
list_options = child_schema.get_strv("options")
result = dict(option.split("=") for option in list_options)
return result
def set_option(info, options):
"""
Store the Keyman keyboard options in DConf as a list of strings
Args:
info: dictionary
packageID (str): package ID
keyboardID (str): keyboard ID
options: dictionary
key and values to store
"""
if "packageID" in info and "keyboardID" in info and options:
# Convert dictionary of options into a list of comma-separated option strings
list_options = []
for key, value in options.items():
list_options.append(key+"="+value)
child_schema = get_child_schema(info)
child_schema.set_strv("options", list_options)
if __name__ == '__main__':
info = {"packageID": "invalid", "keyboardID": "invalid"}
options = get_option(info)
assert(options == {})
info = {"packageID": "sil_cipher_music", "keyboardID": "sil_cipher_music"}
options = get_option(info)
options["set_nfc"] = "1"
set_option(info, options)

View file

@ -15,6 +15,32 @@ class InstallArea(GObject.GEnum):
IA_USER = 3
IA_UNKNOWN = 99
def get_install_area_path(area):
"""
Get the path of an install area.
Args:
area (InstallArea): install area to check
InstallArea.IA_USER: ~/.local/share/keyman
InstallArea.IA_SHARED: /usr/local/share/keyman
InstallArea.IA_OS: /usr/share/keyman
InstallArea.IA_UNKNOWN: /usr/share/keyman
Returns:
string: path of the install area
"""
check_path = "/usr/share/keyman"
if area == InstallArea.IA_USER:
check_path = user_keyman_dir()
elif area == InstallArea.IA_SHARED:
check_path = "/usr/local/share/keyman"
elif area == InstallArea.IA_OS:
check_path = "/usr/share/keyman"
return check_path
def get_installed_kmp(area):
"""
Get list of installed kmp in an install area.
@ -35,13 +61,7 @@ def get_installed_kmp(area):
path (str): base path where keyboard is installed
description (str): Keyboard description
"""
check_paths = []
if area == InstallArea.IA_USER:
check_paths = [ user_keyman_dir() ]
elif area == InstallArea.IA_SHARED:
check_paths = [ "/usr/local/share/keyman" ]
elif area == InstallArea.IA_OS:
check_paths = [ "/usr/share/keyman" ]
check_paths = [ get_install_area_path(area) ]
return get_installed_kmp_paths(check_paths)
@ -57,12 +77,15 @@ def get_installed_kmp_paths(check_paths):
list: Installed kmp
dict: Keyboard
packageID (str): kmp ID
keyboardID (str): Keyboard ID
name (str): Keyboard name
kmpname (str): Keyboard name in local
version (str): Keyboard version
kmpversion (str):
path (str): base path of area where kmp is installed
areapath (str): base path of area where kmp is installed
description (str): Keyboard description
has_kbjson (bool): Keyboard is in the json file
has_kboptions (bool): Keyboard uses options.htm form
"""
installed_keyboards = {}
for keymanpath in check_paths:
@ -96,7 +119,15 @@ def get_installed_kmp_paths(check_paths):
version = md_version
name = md_name
installed_keyboards[o] = { "packageID" : o, "keyboardID" : keyboardID, "name" : name, "kmpname" : md_name, "version" : version, "kmpversion" : md_version, "areapath" : keymanpath, "description" : description, "has_kbjson" : has_kbjson}
has_kboptions = False
if files:
for fileinfo in files:
if fileinfo['name'] == "options.htm":
has_kboptions = True
break
installed_keyboards[o] = {"packageID" : o, "keyboardID" : keyboardID, "name" : name, "kmpname" : md_name,
"version" : version, "kmpversion" : md_version, "areapath" : keymanpath,
"description" : description, "has_kbjson" : has_kbjson, "has_kboptions" : has_kboptions}
return installed_keyboards
@ -117,7 +148,7 @@ def get_kmp_version(packageID):
os_kmp = get_installed_kmp(InstallArea.IA_OS)
if packageID in os_kmp:
version = os_kmp[keyboardid]['version']
version = os_kmp[packageID]['version']
if packageID in shared_kmp:
shared_version = shared_kmp[packageID]['version']
@ -148,7 +179,7 @@ def get_kmp_version_user(packageID):
str: kmp version if kmp ID is installed
None: if not found
"""
user_kmp = get_installed_kmp_user()
user_kmp = get_installed_kmp(InstallArea.IA_USER)
if packageID in user_kmp:
return user_kmp[packageID]['version']
else:

View file

@ -0,0 +1,86 @@
#!/usr/bin/python3
import ast
import gi
import logging
import webbrowser
import urllib.parse
gi.require_version('Gtk', '3.0')
gi.require_version('WebKit2', '4.0')
from gi.repository import Gtk, WebKit2
from urllib.parse import parse_qsl, urlencode
from keyman_config.accelerators import bind_accelerator, init_accel
from keyman_config.dconf_util import get_option, set_option
class OptionsView(Gtk.Window):
def __init__(self, info):
self.accelerators = None
self.optionurl = info["optionurl"]
self.packageID = info["packageID"]
self.keyboardID = info["keyboardID"]
kbtitle = self.packageID + " Settings"
Gtk.Window.__init__(self, title=kbtitle)
init_accel(self)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
# Keyman Desktop gets current option settings from the registry.
# Similarly, we'll read Keyman options from DConf and update optionurl
info = {"packageID": self.packageID, "keyboardID": self.keyboardID}
self.options = get_option(info)
params = ""
if self.options:
# Convert dictionary to query
params = "?" + urlencode(self.options)
s = Gtk.ScrolledWindow()
self.webview = WebKit2.WebView()
self.webview.connect("decide-policy", self.doc_policy)
self.webview.load_uri(self.optionurl + params)
s.add(self.webview)
vbox.pack_start(s, True, True, 0)
hbox = Gtk.Box(spacing=12)
vbox.pack_start(hbox, False, False, 6)
self.add(vbox)
def doc_policy(self, web_view, decision, decision_type):
logging.info("Checking policy")
logging.debug("received policy decision request of type: {0}".format(decision_type.value_name))
if decision_type == WebKit2.PolicyDecisionType.NAVIGATION_ACTION or \
decision_type == WebKit2.PolicyDecisionType.NEW_WINDOW_ACTION:
nav_action = decision.get_navigation_action()
request = nav_action.get_request()
uri = request.get_uri()
logging.debug("nav request is for uri %s", uri)
parsed = urllib.parse.urlparse(uri)
if parsed.scheme == "keyman":
logging.debug("using keyman scheme")
if parsed.path == "cancel":
pass
elif parsed.path == "ok":
logging.debug("submit options form")
# Parse the response for the option_key value and merge the updates
if parsed.query:
updated_options = parse_qsl(parsed.query, keep_blank_values=True)
self.options.update(updated_options)
self.process_option()
self.close()
return True
if not "options.htm" in uri:
logging.debug("opening uri %s in webbrowser")
webbrowser.open(uri)
decision.ignore()
return True
return False
def process_option(self):
# Write the Keyman options to DConf
info = { "packageID": self.packageID, "keyboardID": self.keyboardID}
set_option(info, self.options)

View file

@ -9,8 +9,9 @@ gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk, Gdk, GdkPixbuf, GObject
from keyman_config.list_installed_kmp import get_installed_kmp, InstallArea
from keyman_config.list_installed_kmp import get_install_area_path, get_installed_kmp, InstallArea
from keyman_config.welcome import WelcomeView
from keyman_config.options import OptionsView
from keyman_config.keyboard_details import KeyboardDetailsView
from keyman_config.downloadkeyboard import DownloadKmpWindow
from keyman_config.install_window import InstallKmpWindow, find_keyman_image
@ -68,7 +69,7 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
# window is split left/right hbox
# right is ButtonBox
# possibly 2 ButtonBox in a vbox
# top one with _Remove, _About, ?_Welcome? or ?Read_Me?
# top one with _Remove, _About, ?_Welcome? or ?Read_Me?, _Options
# bottom one with _Download, _Install, Re_fresh, _Close
# left is GtkTreeView - does it need to be inside anything else apart from the hbox?
# with liststore which defines columns
@ -91,7 +92,8 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
str, # version
str, # packageID
int, # enum InstallArea (KmpArea is GObject version)
str) # path to welcome file if it exists or None
str, # path to welcome file if it exists or None
str) # path to options file if it exists or None
# add installed keyboards to the the store e.g.
# treeiter = store.append([GdkPixbuf.Pixbuf.new_from_file_at_size("/usr/local/share/keyman/libtralo/libtralo.ico.png", 16, 16), \
@ -136,6 +138,12 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
self.help_button.connect("clicked", self.on_help_clicked)
bbox_top.add(self.help_button)
self.options_button = Gtk.Button.new_with_mnemonic("_Options")
self.options_button.set_tooltip_text("Settings for keyboard")
self.options_button.connect("clicked", self.on_options_clicked)
self.options_button.set_sensitive(False)
bbox_top.add(self.options_button)
vbox.pack_start(bbox_top, False, False, 12)
@ -176,16 +184,19 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
if install_area == InstallArea.IA_USER:
welcome_file = os.path.join(user_keyboard_dir(kmpdata['packageID']), "welcome.htm")
options_file = os.path.join(user_keyboard_dir(kmpdata['packageID']), "options.htm")
icofile = os.path.join(user_keyboard_dir(kmpdata['packageID']), kmpdata['packageID'] + bmppng)
if not os.path.isfile(icofile):
icofile = os.path.join(user_keyboard_dir(kmpdata['packageID']), kmpdata['keyboardID'] + bmppng)
elif install_area == InstallArea.IA_SHARED:
welcome_file = os.path.join("/usr/local/share/keyman", kmpdata['packageID'], "welcome.htm")
options_file = os.path.join("/usr/local/share/keyman", kmpdata['packageID'], "options.htm")
icofile = os.path.join("/usr/local/share/keyman", kmpdata['packageID'], kmpdata['packageID'] + bmppng)
if not os.path.isfile(icofile):
icofile = os.path.join("/usr/local/share/keyman", kmpdata['packageID'], kmpdata['keyboardID'] + bmppng)
else:
welcome_file = os.path.join("/usr/share/keyman", kmpdata['packageID'], "welcome.htm")
options_file = os.path.join("/usr/share/keyman", kmpdata['packageID'], "options.htm")
icofile = os.path.join("/usr/share/keyman", kmpdata['packageID'], kmpdata['packageID'] + bmppng)
if not os.path.isfile(icofile):
icofile = os.path.join("/usr/share/keyman", kmpdata['packageID'], kmpdata['keyboardID'] + bmppng)
@ -194,13 +205,15 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
if not os.path.isfile(welcome_file):
welcome_file = None
if not os.path.isfile(options_file):
options_file = None
treeiter = store.append([GdkPixbuf.Pixbuf.new_from_file_at_size(icofile, 16, 16), \
kmpdata['name'], \
kmpdata['version'], \
kmpdata['packageID'], \
install_area, \
welcome_file])
welcome_file, \
options_file])
def refresh_installed_kmp(self):
logging.debug("Refreshing listview")
@ -225,13 +238,13 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
self.incomplete_kmp.append(kmpdata)
self.addlistitems(os_kmp, self.store, InstallArea.IA_OS)
def on_tree_selection_changed(self, selection):
model, treeiter = selection.get_selected()
if treeiter is not None:
self.uninstall_button.set_tooltip_text("Uninstall keyboard package " + model[treeiter][1])
self.help_button.set_tooltip_text("Help for keyboard package " + model[treeiter][1])
self.about_button.set_tooltip_text("About keyboard package " + model[treeiter][1])
self.options_button.set_tooltip_text("Settings for keyboard package " + model[treeiter][1])
logging.debug("You selected %s version %s", model[treeiter][1], model[treeiter][2])
if model[treeiter][4] == InstallArea.IA_USER:
logging.debug("Enabling uninstall button for %s in %s", model[treeiter][3], model[treeiter][4])
@ -239,10 +252,16 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
else:
self.uninstall_button.set_sensitive(False)
logging.debug("Disabling uninstall button for %s in %s ", model[treeiter][3], model[treeiter][4])
# welcome file if it exists
if model[treeiter][5]:
self.help_button.set_sensitive(True)
else:
self.help_button.set_sensitive(False)
# options file if it exists
if model[treeiter][6]:
self.options_button.set_sensitive(True)
else:
self.options_button.set_sensitive(False)
def on_help_clicked(self, button):
model, treeiter = self.tree.get_selection().get_selected()
@ -258,6 +277,22 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
else:
logging.info("welcome.htm not available")
def on_options_clicked(self, button):
model, treeiter = self.tree.get_selection().get_selected()
if treeiter is not None:
logging.info("Open options.htm for %s if available", model[treeiter][1])
options_file = model[treeiter][6]
if options_file and os.path.isfile(options_file):
uri_path = pathlib.Path(options_file).as_uri()
logging.info("opening" + uri_path)
# TODO: Determine keyboardID
info = { "optionurl": uri_path, "packageID": model[treeiter][3], "keyboardID": model[treeiter][3] }
w = OptionsView(info)
w.resize(800, 600)
w.show_all()
else:
logging.info("options.htm not available")
def on_uninstall_clicked(self, button):
model, treeiter = self.tree.get_selection().get_selected()
if treeiter is not None:
@ -281,12 +316,7 @@ class ViewInstalledWindow(ViewInstalledWindowBase):
model, treeiter = self.tree.get_selection().get_selected()
if treeiter is not None:
logging.info("Show keyboard details of " + model[treeiter][1])
if model[treeiter][4] == InstallArea.IA_USER:
areapath = user_keyman_dir()
elif model[treeiter][4] == InstallArea.IA_SHARED:
areapath = "/usr/local/share/keyman"
else:
areapath = "/usr/share/keyman"
areapath = get_install_area_path(model[treeiter][4])
kmp = { "name" : model[treeiter][1], "version" : model[treeiter][2], "packageID" : model[treeiter][3], "areapath" : areapath}
w = KeyboardDetailsView(kmp)
w.resize(800, 450)

View file

@ -78,6 +78,9 @@ if [[ "${SUDOINSTALL}" == "yes" ]]; then
echo "keyman-config must be built before it is installed. Run 'make configure' if needed then 'make'"
exit 1
fi
echo "doing sudo glib-compile-schemas for keyman-config"
cp com.keyman.gschema.xml /usr/share/glib-2.0/schemas/
glib-compile-schemas /usr/share/glib-2.0/schemas/
echo "doing sudo install of keyman-config"
make install
elif [[ "${SUDOINSTALL}" == "uninstall" ]]; then