[geary/wip/728002-webkit2: 73/96] Re-enable spell checking in composer.



commit c122651fc0cfd372d96d6e793cd5d5d131f15815
Author: Michael James Gratton <mike vee net>
Date:   Wed Jan 4 03:32:50 2017 +1100

    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.

 desktop/org.gnome.Geary.gschema.xml                |    6 --
 src/client/application/geary-application.vala      |    2 +-
 src/client/application/geary-config.vala           |    5 --
 src/client/application/geary-controller.vala       |    1 +
 src/client/components/client-web-view.vala         |   14 ++++-
 src/client/composer/composer-widget.vala           |   23 +-----
 src/client/composer/spell-check-popover.vala       |   31 +++++----
 src/client/dialogs/preferences-dialog.vala         |   70 ++++++++++++-------
 .../components/client-web-view-test-case.vala      |   10 ++-
 test/client/composer/composer-web-view-test.vala   |    3 +-
 test/js/composer-page-state-test.vala              |    3 +-
 ui/CMakeLists.txt                                  |    2 +-
 ui/{preferences.glade => preferences-dialog.ui}    |   66 ++++---------------
 13 files changed, 106 insertions(+), 130 deletions(-)
---
diff --git a/desktop/org.gnome.Geary.gschema.xml b/desktop/org.gnome.Geary.gschema.xml
index 4a70038..4bcd5d8 100644
--- a/desktop/org.gnome.Geary.gschema.xml
+++ b/desktop/org.gnome.Geary.gschema.xml
@@ -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>
diff --git a/src/client/application/geary-application.vala b/src/client/application/geary-application.vala
index 89ea07c..ebba8a5 100644
--- a/src/client/application/geary-application.vala
+++ b/src/client/application/geary-application.vala
@@ -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();
     }
 
diff --git a/src/client/application/geary-config.vala b/src/client/application/geary-config.vala
index 8df13d8..060d3ef 100644
--- a/src/client/application/geary-config.vala
+++ b/src/client/application/geary-config.vala
@@ -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 {
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index be666a3..e2feefe 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -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
         );
diff --git a/src/client/components/client-web-view.vala b/src/client/components/client-web-view.vala
index 546ebea..52a4f53 100644
--- a/src/client/components/client-web-view.vala
+++ b/src/client/components/client-web-view.vala
@@ -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;
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index 61ed8cb..b5fc3a1 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -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();
diff --git a/src/client/composer/spell-check-popover.vala b/src/client/composer/spell-check-popover.vala
index 0ff1287..c16b896 100644
--- a/src/client/composer/spell-check-popover.vala
+++ b/src/client/composer/spell-check-popover.vala
@@ -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())
diff --git a/src/client/dialogs/preferences-dialog.vala b/src/client/dialogs/preferences-dialog.vala
index 90286b2..1af91a0 100644
--- a/src/client/dialogs/preferences-dialog.vala
+++ b/src/client/dialogs/preferences-dialog.vala
@@ -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();
     }
 }
 
diff --git a/test/client/components/client-web-view-test-case.vala 
b/test/client/components/client-web-view-test-case.vala
index 636a6ad..ddbe9a8 100644
--- a/test/client/components/client-web-view-test-case.vala
+++ b/test/client/components/client-web-view-test-case.vala
@@ -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) {
diff --git a/test/client/composer/composer-web-view-test.vala 
b/test/client/composer/composer-web-view-test.vala
index 034488b..3af1e30 100644
--- a/test/client/composer/composer-web-view-test.vala
+++ b/test/client/composer/composer-web-view-test.vala
@@ -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) {
diff --git a/test/js/composer-page-state-test.vala b/test/js/composer-page-state-test.vala
index e23325b..a4d580d 100644
--- a/test/js/composer-page-state-test.vala
+++ b/test/js/composer-page-state-test.vala
@@ -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) {
diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt
index 14b9d9d..c95061e 100644
--- a/ui/CMakeLists.txt
+++ b/ui/CMakeLists.txt
@@ -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"
diff --git a/ui/preferences.glade b/ui/preferences-dialog.ui
similarity index 80%
rename from ui/preferences.glade
rename to ui/preferences-dialog.ui
index caf4e53..4488e39 100644
--- a/ui/preferences.glade
+++ b/ui/preferences-dialog.ui
@@ -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>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]