[emerillon] Port to GSettings



commit f16828142b07339d2cfd798e9afc5ba5adad0cb7
Author: Å?ukasz JernaÅ? <deejay1 srem org>
Date:   Wed Jul 28 00:06:47 2010 +0200

    Port to GSettings

 configure.ac                            |   18 +--
 data/Makefile.am                        |   31 ++---
 data/emerillon.convert                  |    9 ++
 data/emerillon.schemas.in               |   72 -----------
 data/org.gnome.emerillon.gschema.xml.in |   35 ++++++
 emerillon/config-keys.h                 |   16 ++-
 emerillon/manager.c                     |  202 +++++++++++++------------------
 emerillon/window.c                      |   64 +++++-----
 po/POTFILES.in                          |    2 +-
 9 files changed, 190 insertions(+), 259 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 69bfe09..da17122 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,16 +50,10 @@ GTK_DOC_CHECK([1.14],[--flavour no-tmpl])
 AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
 AC_PATH_PROG(GLIB_MKENUMS, glib-mkenums)
 
-##########
-# GConf. #
-##########
-AM_GCONF_SOURCE_2
-
-AC_PATH_PROG([GCONFTOOL], [gconftool-2], [no])
-
-if test "$GCONFTOOL" = "no"; then
-    AC_MSG_ERROR([gconftool-2 not found])
-fi
+#############
+# GSettings #
+#############
+GLIB_GSETTINGS
 
 ################
 # Translations #
@@ -81,10 +75,10 @@ GNOME_DOC_INIT
 ################
 # Dependencies #
 ################
-GLIB_REQUIRED=2.12.0
+GLIB_REQUIRED=2.25.10
 GTHREAD_REQUIRED=2.12.0
 GTK_REQUIRED=2.20.0
-GCONF_REQUIRED=2.5.90
+GCONF_REQUIRED=2.31.1
 CHAMPLAIN_REQUIRED=0.6.0
 CHAMPLAIN_GTK_REQUIRED=0.6.0
 GEOCLUE_REQUIRED=0.11.1
diff --git a/data/Makefile.am b/data/Makefile.am
index 0529b0d..8d2bc96 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,9 +1,3 @@
- INTLTOOL_SCHEMAS_RULE@
-
-schemas_in_files = emerillon.schemas.in
-schemasdir = $(GCONF_SCHEMA_FILE_DIR)
-schemas_DATA = $(schemas_in_files:.schemas.in=.schemas)
-
 uidir = $(datadir)/emerillon
 UI_FILES = emerillon-ui.xml
 ui_DATA = $(UI_FILES)
@@ -11,14 +5,16 @@ ui_DATA = $(UI_FILES)
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = emerillon.pc
 
-install-data-local:
-if GCONF_SCHEMAS_INSTALL
-	if test -z "$(DESTDIR)" ; then \
-	for p in $(schemas_DATA) ; do \
-	GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(top_builddir)/data/$$p >&1 > /dev/null; \
-	done \
-	fi
-endif
+gsettings_files = \
+	org.gnome.emerillon.gschema.xml.in \
+	$(NULL)
+gsettings_SCHEMAS = $(gsettings_files:.xml.in=.xml)
+ INTLTOOL_XML_NOMERGE_RULE@
+ GSETTINGS_RULES@
+
+
+convertdir=$(datadir)/GConf/gsettings
+convert_DATA=emerillon.convert
 
 @INTLTOOL_DESKTOP_RULE@
 
@@ -30,9 +26,10 @@ desktop_DATA = $(DESKTOP_FILES)
 
 EXTRA_DIST =			\
         $(DESKTOP_IN_FILES)	\
-        $(schemas_in_files)	\
-        $(UI_FILES)
+        $(gsettings_files) 	\
+        $(UI_FILES)         	\
+        $(convert_DATA)
 
 DISTCLEANFILES = 		\
-        $(schemas_DATA)		\
+        $(gsettings_SCHEMAS)		\
         $(DESKTOP_FILES)
diff --git a/data/emerillon.convert b/data/emerillon.convert
new file mode 100644
index 0000000..ac824ad
--- /dev/null
+++ b/data/emerillon.convert
@@ -0,0 +1,9 @@
+[org.gnome.emerillon.ui]
+toolbar = /apps/emerillon/ui/toolbar
+statusbar = /apps/emerillon/ui/statusbar
+sidebar = /apps/emerillon/ui/sidebar
+window-width = /apps/emerillon/ui/window_width
+window-height = /apps/emerillon/ui/window_height
+
+[org.gnome.emerillon.plugins]
+active-plugins = /apps/emerillon/plugins/active-plugins
\ No newline at end of file
diff --git a/data/org.gnome.emerillon.gschema.xml.in b/data/org.gnome.emerillon.gschema.xml.in
new file mode 100644
index 0000000..581be4b
--- /dev/null
+++ b/data/org.gnome.emerillon.gschema.xml.in
@@ -0,0 +1,35 @@
+<schemalist>
+  <schema id="org.gnome.emerillon" path="/apps/emerillon/">
+    <child name="ui" schema="org.gnome.emerillon.ui"/>
+    <child name="plugins" schema="org.gnome.emerillon.plugins"/>
+  </schema>
+  <schema id="org.gnome.emerillon.ui" path="/apps/emerillon/ui/">
+    <key name="toolbar" type="b">
+      <default>true</default>
+      <_summary>Show/hide the window toolbar.</_summary>
+    </key>
+    <key name="statusbar" type="b">
+      <default>true</default>
+      <_summary>Show/hide the window statusbar.</_summary>
+    </key>
+    <key name="sidebar" type="b">
+      <default>true</default>
+      <_summary>Show/hide the window side pane.</_summary>
+    </key>
+    <key name="window-width" type="i">
+      <default>640</default>
+      <_summary>Window width in pixels.</_summary>
+    </key>
+    <key name="window-height" type="i">
+      <default>450</default>
+      <_summary>Window height in pixels.</_summary>
+    </key>
+  </schema>
+  <schema id="org.gnome.emerillon.plugins" path="/apps/emerillon/plugins/">
+    <key name="active-plugins" type="as">
+      <default>[ 'search', 'placemarks' ]</default>
+      <_summary>Active plugins</_summary>
+      <_description>List of active plugins.</_description>
+    </key>
+  </schema>
+</schemalist>
diff --git a/emerillon/config-keys.h b/emerillon/config-keys.h
index 6a9ad29..bb377dc 100644
--- a/emerillon/config-keys.h
+++ b/emerillon/config-keys.h
@@ -19,13 +19,15 @@
 #ifndef __EMERILLON_CONFIG_KEYS_H__
 #define __EMERILLON_CONFIG_KEYS_H__
 
-#define EMERILLON_CONF_DIR                     "/apps/emerillon"
+#define EMERILLON_SCHEMA                       "org.gnome.emerillon"
+#define EMERILLON_SCHEMA_UI                    EMERILLON_SCHEMA ".ui"
+#define EMERILLON_SCHEMA_PLUGINS               EMERILLON_SCHEMA ".plugins"
 
-#define EMERILLON_CONF_UI_TOOLBAR              "/apps/emerillon/ui/toolbar"
-#define EMERILLON_CONF_UI_STATUSBAR            "/apps/emerillon/ui/statusbar"
-#define EMERILLON_CONF_UI_SIDEBAR              "/apps/emerillon/ui/sidebar"
-#define EMERILLON_CONF_UI_WINDOW_WIDTH         "/apps/emerillon/ui/window_width"
-#define EMERILLON_CONF_UI_WINDOW_HEIGHT        "/apps/emerillon/ui/window_height"
-#define EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS  "/apps/emerillon/plugins/active-plugins"
+#define EMERILLON_CONF_UI_TOOLBAR              "toolbar"
+#define EMERILLON_CONF_UI_STATUSBAR            "statusbar"
+#define EMERILLON_CONF_UI_SIDEBAR              "sidebar"
+#define EMERILLON_CONF_UI_WINDOW_WIDTH         "window-width"
+#define EMERILLON_CONF_UI_WINDOW_HEIGHT        "window-height"
+#define EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS  "active-plugins"
 
 #endif /* __EMERILLON_CONFIG_KEYS_H__ */
diff --git a/emerillon/manager.c b/emerillon/manager.c
index 49f4d27..00caf2d 100644
--- a/emerillon/manager.c
+++ b/emerillon/manager.c
@@ -25,7 +25,6 @@
 
 #include <string.h>
 #include <ethos/ethos.h>
-#include <gconf/gconf-client.h>
 
 #include "config-keys.h"
 
@@ -40,7 +39,7 @@ G_DEFINE_TYPE (EmerillonManager, emerillon_manager, ETHOS_TYPE_MANAGER);
 
 struct _EmerillonManagerPrivate
 {
-  GConfClient *client;
+  GSettings *settings_plugins;
 };
 
 static void
@@ -86,25 +85,13 @@ emerillon_manager_constructor (GType type,
   return object;
 }
 
-static void
-gconf_list_free (GSList *conf)
-{
-  GSList *iter;
-
-  for (iter = conf; iter; iter = iter->next)
-    g_free (iter->data);
-
-  g_slist_free (conf);
-}
-
 static gboolean
-is_enabled (GSList *conf, EthosPluginInfo *plugin)
+is_enabled (gchar ** conf, EthosPluginInfo *plugin)
 {
-  GSList *iter;
-
-  for (iter = conf; iter; iter = iter->next)
+  int i;
+  for (i = 0; conf[i] != NULL; i++)
     {
-      if (strcmp (iter->data, ethos_plugin_info_get_id (plugin)) == 0)
+      if (strcmp (conf[i], ethos_plugin_info_get_id (plugin)) == 0)
         return TRUE;
     }
 
@@ -115,141 +102,122 @@ static void
 emerillon_manager_plugin_loaded (EthosManager    *emanager,
                                  EthosPluginInfo *plugin_info)
 {
-  GSList *conf_list;
-  GError *error = NULL;
+  gchar **conf_list;
+  GPtrArray *tmp;
+  GVariant *value;
+  int i;
+  gboolean res;
   EmerillonManager *manager = EMERILLON_MANAGER (emanager);
 
-  conf_list = gconf_client_get_list (manager->priv->client,
-      EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS,
-      GCONF_VALUE_STRING,
-      &error);
+  tmp = g_ptr_array_new_with_free_func (g_free);
+
+  conf_list = g_settings_get_strv (manager->priv->settings_plugins,
+                                   EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS);
 
-  if (error)
-    {
-      g_warning ("gconf: %s", error->message);
-      g_error_free (error);
-      error = NULL;
-      return;
-    }
 
   /* if the plugin is already in the list, stop */
   if (is_enabled (conf_list, plugin_info))
-    {
-      gconf_list_free (conf_list);
-      return;
-    }
-
-  conf_list = g_slist_append (conf_list, g_strdup (ethos_plugin_info_get_id (plugin_info)));
-
-  gconf_client_set_list (manager->priv->client,
-      EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS,
-      GCONF_VALUE_STRING,
-      conf_list,
-      &error);
-
-  if (error)
-    {
-      g_warning ("gconf: %s", error->message);
-      g_error_free (error);
-      error = NULL;
-    }
-
-  gconf_list_free (conf_list);
+  {
+    g_strfreev (conf_list);
+    return;
+  }
+
+  /* rebuilding as a pointer array, sorry */
+  for (i=0;conf_list[i] != NULL;i++)
+    g_ptr_array_add (tmp,g_strdup(conf_list[i]));
+
+  g_ptr_array_add (tmp, g_strdup (ethos_plugin_info_get_id (plugin_info)));
+
+  value = g_variant_new_strv  ((const gchar * const *) tmp->pdata, tmp->len);
+  res = g_settings_set_value (manager->priv->settings_plugins,
+                             EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS,
+                             value);
+  if (!res)
+    g_warning ("gsettings: Key %s is not writable!",
+               EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS);
+
+  g_ptr_array_free (tmp, TRUE);
+  g_strfreev (conf_list);
+  g_variant_unref(value);
 }
 
 static void
 emerillon_manager_plugin_unloaded (EthosManager    *emanager,
                                    EthosPluginInfo *plugin_info)
 {
-  GSList *conf_list;
-  GSList *iter;
-  GError *error = NULL;
+  gboolean res;
+  int i;
+  gchar **conf_list;
+  GPtrArray *tmp;
+  GVariant *value;
+  
   EmerillonManager *manager = EMERILLON_MANAGER (emanager);
 
-  conf_list = gconf_client_get_list (manager->priv->client,
-      EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS,
-      GCONF_VALUE_STRING,
-      &error);
-
-  if (error)
-    {
-      g_warning ("gconf: %s", error->message);
-      g_error_free (error);
-      error = NULL;
-      return;
-    }
+  tmp = g_ptr_array_new_with_free_func (g_free);
 
-  for (iter = conf_list; iter; iter = iter->next)
-    {
-      if (strcmp (iter->data, ethos_plugin_info_get_id (plugin_info)) == 0)
-        conf_list = g_slist_delete_link (conf_list, iter);
-    }
+  conf_list = g_settings_get_strv (manager->priv->settings_plugins,
+                                   EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS);
 
-  gconf_client_set_list (manager->priv->client,
-      EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS,
-      GCONF_VALUE_STRING,
-      conf_list,
-      &error);
+  for (i=0; conf_list[i] != NULL; i++)
+  {
+    if (!strcmp (conf_list[i], ethos_plugin_info_get_id (plugin_info)) == 0)
+      g_ptr_array_add (tmp,g_strdup(conf_list[i]));
+  }
+  value = g_variant_new_strv  ((const gchar * const *) tmp->pdata, tmp->len);
+  res = g_settings_set_value (manager->priv->settings_plugins,
+                             EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS,
+                             value);
 
-  if (error)
-    {
-      g_warning ("gconf: %s", error->message);
-      g_error_free (error);
-      error = NULL;
-    }
+  if (!res)
+    g_warning ("gsettings: Key %s is not writable!",
+               EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS);
 
-  gconf_list_free (conf_list);
+  g_ptr_array_free (tmp, TRUE);
+  g_strfreev (conf_list);
+  g_variant_unref (value);
 }
 
 static void
 emerillon_manager_initialized (EthosManager *emanager)
 {
   GList  *list,
-         *iter;
-  GSList *conf_list;
+  *iter;
+  gchar **conf_list;
   GError *error = NULL;
+
   EmerillonManager *manager = EMERILLON_MANAGER (emanager);
 
   g_return_if_fail (ETHOS_IS_MANAGER (manager));
 
-  manager->priv->client = gconf_client_get_default ();
-  conf_list = gconf_client_get_list (manager->priv->client,
-      EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS,
-      GCONF_VALUE_STRING,
-      &error);
-
-  if (error)
-    {
-      g_warning ("gconf: %s", error->message);
-      g_error_free (error);
-      error = NULL;
-    }
+  manager->priv->settings_plugins = g_settings_new (EMERILLON_SCHEMA_PLUGINS);
+  conf_list = g_settings_get_strv (manager->priv->settings_plugins,
+                                   EMERILLON_CONF_PLUGINS_ACTIVE_PLUGINS);
 
   list = ethos_manager_get_plugin_info (emanager);
   for (iter = list; iter; iter = iter->next)
+  {
+    if (ethos_plugin_info_get_active (iter->data))
+    {
+      continue;
+    }
+    else if (is_enabled (conf_list, iter->data) &&
+             !ethos_manager_load_plugin (emanager, iter->data, &error))
     {
-      if (ethos_plugin_info_get_active (iter->data))
-        {
-          continue;
-        }
-      else if (is_enabled (conf_list, iter->data) &&
-               !ethos_manager_load_plugin (emanager, iter->data, &error))
-        {
-          g_warning ("%s: %s",
-                     ethos_plugin_info_get_id (iter->data),
-                     error ? error->message : "Error loading");
-
-          if (error)
-            {
-              //ethos_plugin_info_add_error (iter->data, error);
-              g_error_free (error);
-              error = NULL;
-            }
-        }
+      g_warning ("%s: %s",
+                 ethos_plugin_info_get_id (iter->data),
+                 error ? error->message : "Error loading");
+
+      if (error)
+      {
+        //ethos_plugin_info_add_error (iter->data, error);
+        g_error_free (error);
+        error = NULL;
+      }
     }
+  }
 
   g_list_free (list);
-  gconf_list_free (conf_list);
+  g_strfreev (conf_list);
 }
 
 static void
diff --git a/emerillon/window.c b/emerillon/window.c
index 83d62c5..260163a 100644
--- a/emerillon/window.c
+++ b/emerillon/window.c
@@ -27,7 +27,6 @@
 
 #include <champlain/champlain.h>
 #include <champlain-gtk/champlain-gtk.h>
-#include <gconf/gconf-client.h>
 #include <geoclue/geoclue-master.h>
 #include <geoclue/geoclue-position.h>
 #include <glib/gi18n.h>
@@ -58,7 +57,7 @@ struct _EmerillonWindowPrivate
 
   GtkActionGroup *main_actions;
 
-  GConfClient *client;
+  GSettings *settings_ui;
 
 
   guint tooltip_message_context_id;
@@ -204,13 +203,11 @@ emerillon_window_init (EmerillonWindow *self)
 
   self->priv = EMERILLON_WINDOW_GET_PRIVATE (self);
 
-  self->priv->position_auto_update = FALSE;
 
-  /* GConf. */
-  self->priv->client = gconf_client_get_default ();
+  self->priv->position_auto_update = FALSE;
 
-  gconf_client_add_dir (self->priv->client, EMERILLON_CONF_DIR,
-      GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+  /* GSettings. */
+  self->priv->settings_ui = g_settings_new (EMERILLON_SCHEMA_UI);
 
   /* Window setup. */
   geometry.min_width = 400;
@@ -219,10 +216,10 @@ emerillon_window_init (EmerillonWindow *self)
       &geometry,GDK_HINT_MIN_SIZE);
 
   /* Set the window size */
-  width = gconf_client_get_int (self->priv->client,
-      EMERILLON_CONF_UI_WINDOW_WIDTH, NULL);
-  height = gconf_client_get_int (self->priv->client,
-      EMERILLON_CONF_UI_WINDOW_HEIGHT, NULL);
+  width = g_settings_get_int (self->priv->settings_ui,
+      EMERILLON_CONF_UI_WINDOW_WIDTH);
+  height = g_settings_get_int (self->priv->settings_ui,
+      EMERILLON_CONF_UI_WINDOW_HEIGHT);
 
   if (width > 0 && height > 0)
     gtk_window_set_default_size (GTK_WINDOW (self), width, height);
@@ -272,19 +269,17 @@ emerillon_window_dispose (GObject *object)
       self->priv->main_actions = NULL;
     }
 
-  if (self->priv->client)
-  {
-    /* Save the window size */
-    gtk_window_get_size (GTK_WINDOW (self), &width, &height);
-    width = gconf_client_set_int (self->priv->client,
-                                  EMERILLON_CONF_UI_WINDOW_WIDTH, width, NULL);
-    height = gconf_client_set_int (self->priv->client,
-                                   EMERILLON_CONF_UI_WINDOW_HEIGHT, height, NULL);
-
-    gconf_client_remove_dir (self->priv->client, EMERILLON_CONF_DIR, NULL);
-    g_object_unref (self->priv->client);
-    self->priv->client = NULL;
-  }
+  if (self->priv->settings_ui)
+    {
+      /* Save the window size */
+      gtk_window_get_size (GTK_WINDOW (self), &width, &height);
+      width = g_settings_set_int (self->priv->settings_ui,
+                                  EMERILLON_CONF_UI_WINDOW_WIDTH, width);
+      height = g_settings_set_int (self->priv->settings_ui,
+                                   EMERILLON_CONF_UI_WINDOW_HEIGHT, height);
+      g_object_unref (self->priv->settings_ui);
+      self->priv->settings_ui = NULL;
+    }
 
   if (self->priv->geoclue_client)
     {
@@ -409,6 +404,9 @@ zoom_changed_cb (GtkWidget *widget,
   gtk_action_set_sensitive (zoom_out_action, zoom_level > min_zoom_level);
 }
 
+/* TODO: use g_settings_bind instead of manual visibility switching
+ * see also cmd_show_hide_bar()
+*/
 static void
 update_ui_visibility (EmerillonWindow *self)
 {
@@ -416,8 +414,8 @@ update_ui_visibility (EmerillonWindow *self)
   GtkAction *action;
 
   /* Toolbar. */
-  visible = gconf_client_get_bool (self->priv->client,
-      EMERILLON_CONF_UI_TOOLBAR, NULL);
+  visible = g_settings_get_boolean (self->priv->settings_ui,
+      EMERILLON_CONF_UI_TOOLBAR);
   action = gtk_ui_manager_get_action (self->priv->ui_manager,
       "/MainMenu/View/ToolbarToggle");
   g_assert (action != NULL);
@@ -425,8 +423,8 @@ update_ui_visibility (EmerillonWindow *self)
   g_object_set (G_OBJECT (self->priv->toolbar), "visible", visible, NULL);
 
   /* Statusbar. */
-  visible = gconf_client_get_bool (self->priv->client,
-      EMERILLON_CONF_UI_STATUSBAR, NULL);
+  visible = g_settings_get_boolean (self->priv->settings_ui,
+      EMERILLON_CONF_UI_STATUSBAR);
   action = gtk_ui_manager_get_action (self->priv->ui_manager,
       "/MainMenu/View/StatusbarToggle");
   g_assert (action != NULL);
@@ -434,8 +432,8 @@ update_ui_visibility (EmerillonWindow *self)
   g_object_set (G_OBJECT (self->priv->statusbar), "visible", visible, NULL);
 
   /* Sidebar. */
-  visible = gconf_client_get_bool (self->priv->client,
-      EMERILLON_CONF_UI_SIDEBAR, NULL);
+  visible = g_settings_get_boolean (self->priv->settings_ui,
+      EMERILLON_CONF_UI_SIDEBAR);
   action = gtk_ui_manager_get_action (self->priv->ui_manager,
       "/MainMenu/View/SidebarToggle");
   g_assert (action != NULL);
@@ -597,7 +595,7 @@ cmd_show_hide_bar (GtkAction *action,
   else
       gtk_widget_hide (target_widget);
 
-  gconf_client_set_bool (self->priv->client, target_conf_key, visible, NULL);
+  g_settings_set_boolean (self->priv->settings_ui, target_conf_key, visible);
 }
 
 static void
@@ -720,8 +718,8 @@ sidebar_visibility_changed_cb (GtkWidget *widget,
 
   visible = gtk_widget_get_visible (self->priv->sidebar);
 
-  gconf_client_set_bool (self->priv->client, EMERILLON_CONF_UI_SIDEBAR,
-      visible, NULL);
+  g_settings_set_boolean (self->priv->settings_ui, EMERILLON_CONF_UI_SIDEBAR,
+      visible);
 
   action = gtk_action_group_get_action (self->priv->main_actions,
       "ViewSidebar");
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6cb7e70..420458a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,8 +1,8 @@
 # List of source files containing translatable strings.
 # Please keep this file sorted alphabetically.
 [encoding: UTF-8]
-data/emerillon.schemas.in
 data/emerillon.desktop.in.in
+data/org.gnome.emerillon.gschema.xml.in
 emerillon/main.c
 emerillon/sidebar.c
 emerillon/window.c



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