Re-enable spell checking in composer.

* src/client/application/geary-config.vala (Configuration): Remove
  spell-check setting, we can just get it from the list of visible
  languages instead. Update the schema.

* src/client/components/client-web-view.vala (WebView::init_web_context):
  Pass in a config object, use that to init WebKit's spell checking on
  the WebContext now that is a global configuration, update it when the
  config changes, update call sites.

* src/client/composer/composer-widget.vala (ComposerWidget): Remove
  WK1-syle spell checking settings prefs.

* src/client/composer/spell-check-popover.vala (SpellCheckPopover): Pass
  a config object in so we don't have to use the global app singleton
  instance.

* src/client/dialogs/preferences-dialog.vala (PreferencesDialog):
  Modernise by converting into a widget template.

* test/client/components/client-web-view-test-case.vala (TestCase):
  Construct a config object as a fixture, use it to init the WebContext
  and make it avalaible to subclasses & update subclasses.

* ui/preferences-dialog.ui: Moved from preferences.dialog, remove spell
  check preference.
This commit is contained in:
Michael James Gratton 2017-01-04 03:32:50 +11:00
parent 6171ff2ebd
commit f69c461955
13 changed files with 106 additions and 130 deletions

View file

@ -62,12 +62,6 @@
<description>True if we should display a short preview of each message.</description>
</key>
<key name="spell-check" type="b">
<default>true</default>
<summary>enable inline spell checking</summary>
<description>True to spell check while typing.</description>
</key>
<key name="spell-check-languages" type="as">
<default>[]</default>
<summary>Languages that shall be used in the spell checker</summary>

View file

@ -470,7 +470,7 @@ public class GearyApplication : Gtk.Application {
}
private void on_activate_preferences() {
PreferencesDialog dialog = new PreferencesDialog(get_active_window());
PreferencesDialog dialog = new PreferencesDialog(get_active_window(), this);
dialog.run();
}

View file

@ -19,7 +19,6 @@ public class Configuration {
public const string MESSAGES_PANE_POSITION_KEY = "messages-pane-position";
public const string AUTOSELECT_KEY = "autoselect";
public const string DISPLAY_PREVIEW_KEY = "display-preview";
public const string SPELL_CHECK_KEY = "spell-check";
public const string PLAY_SOUNDS_KEY = "play-sounds";
public const string SHOW_NOTIFICATIONS_KEY = "show-notifications";
public const string STARTUP_NOTIFICATIONS_KEY = "startup-notifications";
@ -104,10 +103,6 @@ public class Configuration {
public bool display_preview {
get { return settings.get_boolean(DISPLAY_PREVIEW_KEY); }
}
public bool spell_check {
get { return settings.get_boolean(SPELL_CHECK_KEY); }
}
public string[] spell_check_languages {
owned get {

View file

@ -190,6 +190,7 @@ public class GearyController : Geary.BaseObject {
// Initialise WebKit and WebViews
ClientWebView.init_web_context(
this.application.config,
this.application.get_web_extensions_dir(),
Args.log_debug
);

View file

@ -39,7 +39,8 @@ public class ClientWebView : WebKit.WebView {
/**
* Initialises WebKit.WebContext for use by the client.
*/
public static void init_web_context(File web_extension_dir,
public static void init_web_context(Configuration config,
File web_extension_dir,
bool enable_logging) {
WebKit.WebContext context = WebKit.WebContext.get_default();
context.set_process_model(WebKit.ProcessModel.SHARED_SECONDARY_PROCESS);
@ -64,6 +65,11 @@ public class ClientWebView : WebKit.WebView {
new Variant.boolean(enable_logging)
);
});
update_spellcheck(context, config);
config.settings.changed[Configuration.SPELL_CHECK_LANGUAGES].connect(() => {
update_spellcheck(context, config);
});
}
/**
@ -123,6 +129,12 @@ public class ClientWebView : WebKit.WebView {
);
}
private static inline void update_spellcheck(WebKit.WebContext context,
Configuration config) {
context.set_spell_checking_enabled(config.spell_check_languages.length > 0);
context.set_spell_checking_languages(config.spell_check_languages);
}
private static inline uint to_wk2_font_size(Pango.FontDescription font) {
Gdk.Screen? screen = Gdk.Screen.get_default();
double dpi = screen != null ? screen.get_resolution() : 96.0;

View file

@ -467,16 +467,6 @@ public class ComposerWidget : Gtk.EventBox {
this.editor.load_html(this.body_html, this.signature_html, this.top_posting);
GearyApplication.instance.config.settings.changed[Configuration.SPELL_CHECK_KEY].connect(
on_spell_check_changed);
// WebKit.Settings s = this.editor.settings;
// s.enable_spell_checking = GearyApplication.instance.config.spell_check;
// s.spell_checking_languages = string.joinv(
// ",", GearyApplication.instance.config.spell_check_languages
// );
// this.editor.settings = s;
this.editor_scrolled.add(editor);
// Place the message area before the compose toolbar in the focus chain, so that
@ -792,7 +782,6 @@ public class ComposerWidget : Gtk.EventBox {
// This is safe to call even when this connection hasn't been made.
realize.disconnect(on_load_finished_and_realized);
on_spell_check_changed();
update_actions();
this.actions.change_action_state(ACTION_SHOW_EXTENDED, false);
@ -1833,11 +1822,6 @@ public class ComposerWidget : Gtk.EventBox {
update_message_overlay_label_style();
}
private void on_spell_check_changed() {
//this.editor.settings.enable_spell_checking = GearyApplication.instance.config.spell_check;
//get_action(ACTION_SELECT_DICTIONARY).set_enabled(this.editor.settings.enable_spell_checking);
}
// This overrides the keypress handling for the *widget*; the WebView editor's keypress overrides
// are handled by on_editor_key_press
public override bool key_press_event(Gdk.EventKey event) {
@ -1910,10 +1894,11 @@ public class ComposerWidget : Gtk.EventBox {
private void on_select_dictionary(SimpleAction action, Variant? param) {
if (this.spell_check_popover == null) {
this.spell_check_popover = new SpellCheckPopover(select_dictionary_button);
this.spell_check_popover = new SpellCheckPopover(
this.select_dictionary_button, this.config
);
this.spell_check_popover.selection_changed.connect((active_langs) => {
//this.editor.settings.spell_checking_languages = string.joinv(",", active_langs);
GearyApplication.instance.config.spell_check_languages = active_langs;
this.config.spell_check_languages = active_langs;
});
}
this.spell_check_popover.toggle();

View file

@ -21,6 +21,7 @@ public class SpellCheckPopover {
private Gtk.SearchEntry search_box;
private Gtk.ScrolledWindow view;
private Gtk.Box content;
private Configuration config;
private enum SpellCheckStatus {
INACTIVE,
@ -50,9 +51,12 @@ public class SpellCheckPopover {
private Gtk.Image active_image;
private Gtk.Button remove_button;
private SpellCheckStatus lang_active = SpellCheckStatus.INACTIVE;
private Configuration config;
public SpellCheckLangRow (string lang_code) {
public SpellCheckLangRow (string lang_code, Configuration config) {
this.lang_code = lang_code;
this.config = config;
Gtk.Box box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
lang_name = International.language_name_from_locale(lang_code);
@ -78,12 +82,12 @@ public class SpellCheckPopover {
remove_button.clicked.connect(on_remove_clicked);
is_lang_visible = false;
foreach (string visible_lang in GearyApplication.instance.config.spell_check_visible_languages) {
foreach (string visible_lang in this.config.spell_check_visible_languages) {
if (visible_lang == lang_code)
is_lang_visible = true;
}
foreach (string active_lang in GearyApplication.instance.config.spell_check_languages) {
foreach (string active_lang in this.config.spell_check_languages) {
if (active_lang == lang_code)
lang_active = SpellCheckStatus.ACTIVE;
}
@ -125,17 +129,17 @@ public class SpellCheckPopover {
set_lang_active(SpellCheckStatus.INACTIVE);
if (is_lang_visible) {
string[] visible_langs = GearyApplication.instance.config.spell_check_visible_languages;
string[] visible_langs = this.config.spell_check_visible_languages;
visible_langs += lang_code;
GearyApplication.instance.config.spell_check_visible_languages = visible_langs;
this.config.spell_check_visible_languages = visible_langs;
}
else {
string[] visible_langs = {};
foreach (string lang in GearyApplication.instance.config.spell_check_visible_languages) {
foreach (string lang in this.config.spell_check_visible_languages) {
if (lang != lang_code)
visible_langs += lang;
}
GearyApplication.instance.config.spell_check_visible_languages = visible_langs;
this.config.spell_check_visible_languages = visible_langs;
}
visibility_changed();
@ -154,9 +158,9 @@ public class SpellCheckPopover {
case SpellCheckStatus.ACTIVE:
// If the lang is not visible make it visible now
if (!is_lang_visible) {
string[] visible_langs = GearyApplication.instance.config.spell_check_visible_languages;
string[] visible_langs = this.config.spell_check_visible_languages;
visible_langs += lang_code;
GearyApplication.instance.config.spell_check_visible_languages = visible_langs;
this.config.spell_check_visible_languages = visible_langs;
is_lang_visible = true;
}
break;
@ -189,9 +193,10 @@ public class SpellCheckPopover {
}
}
public SpellCheckPopover(Gtk.Widget button) {
popover = new Gtk.Popover(button);
selected_rows = new GLib.GenericSet<string>(GLib.str_hash, GLib.str_equal);
public SpellCheckPopover(Gtk.Widget button, Configuration config) {
this.popover = new Gtk.Popover(button);
this.config = config;
this.selected_rows = new GLib.GenericSet<string>(GLib.str_hash, GLib.str_equal);
setup_popover();
}
@ -219,7 +224,7 @@ public class SpellCheckPopover {
langs_list = new Gtk.ListBox();
langs_list.set_selection_mode(Gtk.SelectionMode.NONE);
foreach (string lang in languages) {
SpellCheckLangRow row = new SpellCheckLangRow(lang);
SpellCheckLangRow row = new SpellCheckLangRow(lang, this.config);
langs_list.add(row);
if (row.is_lang_active())

View file

@ -4,34 +4,52 @@
* (version 2.1 or later). See the COPYING file in this distribution.
*/
public class PreferencesDialog : Object {
private Gtk.Dialog dialog;
public PreferencesDialog(Gtk.Window parent) {
Gtk.Builder builder = GearyApplication.instance.create_builder("preferences.glade");
// Get all of the dialog elements.
dialog = builder.get_object("dialog") as Gtk.Dialog;
dialog.set_transient_for(parent);
dialog.set_modal(true);
Configuration config = GearyApplication.instance.config;
config.bind(Configuration.AUTOSELECT_KEY, builder.get_object("autoselect"), "active");
config.bind(Configuration.DISPLAY_PREVIEW_KEY, builder.get_object("display_preview"), "active");
config.bind(Configuration.FOLDER_LIST_PANE_HORIZONTAL_KEY,
builder.get_object("three_pane_view"), "active");
config.bind(Configuration.SPELL_CHECK_KEY, builder.get_object("spell_check"), "active");
config.bind(Configuration.PLAY_SOUNDS_KEY, builder.get_object("play_sounds"), "active");
config.bind(Configuration.SHOW_NOTIFICATIONS_KEY, builder.get_object("show_notifications"), "active");
config.bind(Configuration.STARTUP_NOTIFICATIONS_KEY, builder.get_object("startup_notifications"), "active");
[GtkTemplate (ui = "/org/gnome/Geary/preferences-dialog.ui")]
public class PreferencesDialog : Gtk.Dialog {
[GtkChild]
private Gtk.CheckButton autoselect;
[GtkChild]
private Gtk.CheckButton display_preview;
[GtkChild]
private Gtk.CheckButton three_pane_view;
[GtkChild]
private Gtk.CheckButton play_sounds;
[GtkChild]
private Gtk.CheckButton show_notifications;
[GtkChild]
private Gtk.CheckButton startup_notifications;
[GtkChild]
private Gtk.HeaderBar header;
private GearyApplication app;
public PreferencesDialog(Gtk.Window parent, GearyApplication app) {
set_transient_for(parent);
set_titlebar(this.header);
this.app = app;
Configuration config = app.config;
config.bind(Configuration.AUTOSELECT_KEY, autoselect, "active");
config.bind(Configuration.DISPLAY_PREVIEW_KEY, display_preview, "active");
config.bind(Configuration.FOLDER_LIST_PANE_HORIZONTAL_KEY, three_pane_view, "active");
config.bind(Configuration.PLAY_SOUNDS_KEY, play_sounds, "active");
config.bind(Configuration.SHOW_NOTIFICATIONS_KEY, show_notifications, "active");
config.bind(Configuration.STARTUP_NOTIFICATIONS_KEY, startup_notifications, "active");
}
public void run() {
public new void run() {
// Sync startup notification option with file state
GearyApplication.instance.controller.autostart_manager.sync_with_config();
dialog.show_all();
dialog.run();
dialog.destroy();
this.app.controller.autostart_manager.sync_with_config();
base.run();
destroy();
}
}

View file

@ -10,14 +10,20 @@ extern const string _BUILD_ROOT_DIR;
public abstract class ClientWebViewTestCase<V> : Gee.TestCase {
protected V test_view = null;
protected V? test_view = null;
protected Configuration? config = null;
public ClientWebViewTestCase(string name) {
base(name);
}
public override void set_up() {
ClientWebView.init_web_context(File.new_for_path(_BUILD_ROOT_DIR).get_child("src"), true);
this.config = new Configuration(GearyApplication.APP_ID);
ClientWebView.init_web_context(
this.config,
File.new_for_path(_BUILD_ROOT_DIR).get_child("src"),
true
);
try {
ClientWebView.load_scripts();
} catch (Error err) {

View file

@ -152,8 +152,7 @@ long, long, long, long, long, long, long, long, long, long,
} catch (Error err) {
assert_not_reached();
}
Configuration config = new Configuration(GearyApplication.APP_ID);
return new ComposerWebView(config);
return new ComposerWebView(this.config);
}
protected override void load_body_fixture(string? html = null) {

View file

@ -152,8 +152,7 @@ class ComposerPageStateTest : ClientWebViewTestCase<ComposerWebView> {
} catch (Error err) {
assert_not_reached();
}
Configuration config = new Configuration(GearyApplication.APP_ID);
return new ComposerWebView(config);
return new ComposerWebView(this.config);
}
protected override void load_body_fixture(string? html = null) {

View file

@ -29,7 +29,7 @@ set(RESOURCE_LIST
STRIPBLANKS "main-toolbar.ui"
STRIPBLANKS "main-window.ui"
STRIPBLANKS "password-dialog.glade"
STRIPBLANKS "preferences.glade"
STRIPBLANKS "preferences-dialog.ui"
STRIPBLANKS "remove_confirm.glade"
STRIPBLANKS "toolbar_empty_menu.ui"
STRIPBLANKS "toolbar_mark_menu.ui"

View file

@ -1,18 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.14"/>
<object class="GtkDialog" id="dialog">
<template class="PreferencesDialog" parent="GtkDialog">
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="window_position">center-on-parent</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
</object>
@ -24,11 +25,11 @@
</packing>
</child>
<child>
<object class="GtkGrid" id="grid1">
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label1">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_end">5</property>
@ -103,44 +104,7 @@
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_end">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="label" translatable="yes">Composer</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="spell_check">
<property name="label" translatable="yes">Enable _spell checking</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="margin_start">12</property>
<property name="margin_end">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_end">5</property>
@ -154,7 +118,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
@ -173,7 +137,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">7</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
@ -192,7 +156,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">8</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
@ -212,12 +176,9 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">9</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
@ -228,12 +189,13 @@
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<object class="GtkHeaderBar" id="header">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Preferences</property>
<property name="has_subtitle">False</property>
<property name="show_close_button">True</property>
</object>
</child>
</object>
</template>
</interface>