[evolution] Calendar: Make it possible to assign email address to On This Computer sources



commit 419f12ea0416163459368158f616fa288971df0f
Author: Milan Crha <mcrha redhat com>
Date:   Fri Oct 30 09:05:54 2020 +0100

    Calendar: Make it possible to assign email address to On This Computer sources
    
    This email address can be used as a default organizer or an email reminder
    address.

 src/calendar/gui/e-comp-editor-page-general.c      |  74 +-------
 src/e-util/CMakeLists.txt                          |   2 +
 src/e-util/e-ellipsized-combo-box-text.c           | 113 ++++++++++++
 src/e-util/e-ellipsized-combo-box-text.h           |  70 +++++++
 src/e-util/e-util.h                                |   1 +
 src/modules/cal-config-local/CMakeLists.txt        |   4 +-
 .../cal-config-local/evolution-cal-config-local.c  | 203 ++++++++++++---------
 7 files changed, 305 insertions(+), 162 deletions(-)
---
diff --git a/src/calendar/gui/e-comp-editor-page-general.c b/src/calendar/gui/e-comp-editor-page-general.c
index edc56196b4..abfcddf649 100644
--- a/src/calendar/gui/e-comp-editor-page-general.c
+++ b/src/calendar/gui/e-comp-editor-page-general.c
@@ -73,78 +73,6 @@ enum {
 
 G_DEFINE_TYPE (ECompEditorPageGeneral, e_comp_editor_page_general, E_TYPE_COMP_EDITOR_PAGE)
 
-/* Begin of customized GtkComboBoxText, which doesn't use width as the longest text in it */
-
-typedef struct _ECEPGeneralOrganizerComboBox {
-       GtkComboBoxText parent;
-} ECEPGeneralOrganizerComboBox;
-
-typedef struct _ECEPGeneralOrganizerComboBoxClass {
-       GtkComboBoxTextClass parent_class;
-} ECEPGeneralOrganizerComboBoxClass;
-
-GType ecep_general_organizer_combo_box_get_type (void) G_GNUC_CONST;
-
-G_DEFINE_TYPE (ECEPGeneralOrganizerComboBox, ecep_general_organizer_combo_box, GTK_TYPE_COMBO_BOX_TEXT)
-
-static void
-ecep_general_organizer_combo_box_get_preferred_width (GtkWidget *widget,
-                                                     gint *minimum_width,
-                                                     gint *natural_width)
-{
-       GTK_WIDGET_CLASS (ecep_general_organizer_combo_box_parent_class)->get_preferred_width (widget, 
minimum_width, natural_width);
-
-       if (*natural_width > 250)
-               *natural_width = 225;
-}
-
-static void
-ecep_general_organizer_combo_box_constructed (GObject *object)
-{
-       GList *cells, *link;
-
-       G_OBJECT_CLASS (ecep_general_organizer_combo_box_parent_class)->constructed (object);
-
-       cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (object));
-       for (link = cells; link; link = g_list_next (link)) {
-               if (GTK_IS_CELL_RENDERER_TEXT (link->data)) {
-                       g_object_set (link->data,
-                               "ellipsize", PANGO_ELLIPSIZE_END,
-                               NULL);
-               }
-       }
-
-       g_list_free (cells);
-}
-
-static void
-ecep_general_organizer_combo_box_class_init (ECEPGeneralOrganizerComboBoxClass *klass)
-{
-       GtkWidgetClass *widget_class;
-       GObjectClass *object_class;
-
-       widget_class = GTK_WIDGET_CLASS (klass);
-       widget_class->get_preferred_width = ecep_general_organizer_combo_box_get_preferred_width;
-
-       object_class = G_OBJECT_CLASS (klass);
-       object_class->constructed = ecep_general_organizer_combo_box_constructed;
-}
-
-static void
-ecep_general_organizer_combo_box_init (ECEPGeneralOrganizerComboBox *object)
-{
-}
-
-static GtkWidget *
-ecep_general_organizer_combo_box_new (void)
-{
-       return g_object_new (ecep_general_organizer_combo_box_get_type (),
-               "has-entry", FALSE,
-               NULL);
-}
-
-/* End of customized GtkComboBoxText, which doesn't use width as the longest text in it */
-
 static void ecep_general_sensitize_widgets (ECompEditorPage *page,
                                            gboolean force_insensitive);
 
@@ -1353,7 +1281,7 @@ ecep_general_constructed (GObject *object)
 
        page_general->priv->organizer_hbox = widget;
 
-       widget = ecep_general_organizer_combo_box_new ();
+       widget = e_ellipsized_combo_box_text_new (FALSE);
        g_object_set (G_OBJECT (widget),
                "hexpand", TRUE,
                "halign", GTK_ALIGN_FILL,
diff --git a/src/e-util/CMakeLists.txt b/src/e-util/CMakeLists.txt
index e138c95ab2..2fe304d2d3 100644
--- a/src/e-util/CMakeLists.txt
+++ b/src/e-util/CMakeLists.txt
@@ -113,6 +113,7 @@ set(SOURCES
        e-destination-store.c
        e-dialog-utils.c
        e-dialog-widgets.c
+       e-ellipsized-combo-box-text.c
        e-emoticon-action.c
        e-emoticon-chooser-menu.c
        e-emoticon-chooser.c
@@ -387,6 +388,7 @@ set(HEADERS
        e-destination-store.h
        e-dialog-utils.h
        e-dialog-widgets.h
+       e-ellipsized-combo-box-text.h
        e-emoticon-action.h
        e-emoticon-chooser-menu.h
        e-emoticon-chooser.h
diff --git a/src/e-util/e-ellipsized-combo-box-text.c b/src/e-util/e-ellipsized-combo-box-text.c
new file mode 100644
index 0000000000..b67dbe1731
--- /dev/null
+++ b/src/e-util/e-ellipsized-combo-box-text.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "evolution-config.h"
+
+#include <gtk/gtk.h>
+
+#include "e-ellipsized-combo-box-text.h"
+
+struct _EEllipsizedComboBoxTextPrivate {
+       gint max_natural_width;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (EEllipsizedComboBoxText, e_ellipsized_combo_box_text, GTK_TYPE_COMBO_BOX_TEXT)
+
+static void
+ellipsized_combo_box_text_get_preferred_width (GtkWidget *widget,
+                                              gint *minimum_width,
+                                              gint *natural_width)
+{
+       EEllipsizedComboBoxText *combo_box = E_ELLIPSIZED_COMBO_BOX_TEXT (widget);
+
+       GTK_WIDGET_CLASS (e_ellipsized_combo_box_text_parent_class)->get_preferred_width (widget, 
minimum_width, natural_width);
+
+       if (*natural_width > combo_box->priv->max_natural_width + (25 * gtk_widget_get_scale_factor (widget)))
+               *natural_width = combo_box->priv->max_natural_width;
+}
+
+static void
+ellipsized_combo_box_text_constructed (GObject *object)
+{
+       GList *cells, *link;
+
+       G_OBJECT_CLASS (e_ellipsized_combo_box_text_parent_class)->constructed (object);
+
+       cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (object));
+       for (link = cells; link; link = g_list_next (link)) {
+               if (GTK_IS_CELL_RENDERER_TEXT (link->data)) {
+                       g_object_set (link->data,
+                               "ellipsize", PANGO_ELLIPSIZE_END,
+                               NULL);
+               }
+       }
+
+       g_list_free (cells);
+}
+
+static void
+e_ellipsized_combo_box_text_class_init (EEllipsizedComboBoxTextClass *klass)
+{
+       GtkWidgetClass *widget_class;
+       GObjectClass *object_class;
+
+       widget_class = GTK_WIDGET_CLASS (klass);
+       widget_class->get_preferred_width = ellipsized_combo_box_text_get_preferred_width;
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->constructed = ellipsized_combo_box_text_constructed;
+}
+
+static void
+e_ellipsized_combo_box_text_init (EEllipsizedComboBoxText *combo_box)
+{
+       combo_box->priv = e_ellipsized_combo_box_text_get_instance_private (combo_box);
+       combo_box->priv->max_natural_width = 225;
+}
+
+GtkWidget *
+e_ellipsized_combo_box_text_new (gboolean has_entry)
+{
+       return g_object_new (e_ellipsized_combo_box_text_get_type (),
+               "has-entry", has_entry,
+               NULL);
+}
+
+gint
+e_ellipsized_combo_box_text_get_max_natural_width (EEllipsizedComboBoxText *combo_box)
+{
+       g_return_val_if_fail (E_IS_ELLIPSIZED_COMBO_BOX_TEXT (combo_box), -1);
+
+       return combo_box->priv->max_natural_width;
+}
+
+void
+e_ellipsized_combo_box_text_set_max_natural_width (EEllipsizedComboBoxText *combo_box,
+                                                  gint max_natural_width)
+{
+       g_return_if_fail (E_IS_ELLIPSIZED_COMBO_BOX_TEXT (combo_box));
+
+       if (combo_box->priv->max_natural_width != max_natural_width) {
+               GtkWidget *widget;
+
+               combo_box->priv->max_natural_width = max_natural_width;
+
+               widget = GTK_WIDGET (combo_box);
+
+               if (gtk_widget_get_realized (widget))
+                       gtk_widget_queue_resize (widget);
+       }
+}
diff --git a/src/e-util/e-ellipsized-combo-box-text.h b/src/e-util/e-ellipsized-combo-box-text.h
new file mode 100644
index 0000000000..3076a9e83b
--- /dev/null
+++ b/src/e-util/e-ellipsized-combo-box-text.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_ELLIPSIZED_COMBO_BOX_TEXT_H
+#define E_ELLIPSIZED_COMBO_BOX_TEXT_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ELLIPSIZED_COMBO_BOX_TEXT \
+       (e_ellipsized_combo_box_text_get_type ())
+#define E_ELLIPSIZED_COMBO_BOX_TEXT(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_ELLIPSIZED_COMBO_BOX_TEXT, EEllipsizedComboBoxText))
+#define E_ELLIPSIZED_COMBO_BOX_TEXT_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_ELLIPSIZED_COMBO_BOX_TEXT, EEllipsizedComboBoxTextClass))
+#define E_IS_ELLIPSIZED_COMBO_BOX_TEXT(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_ELLIPSIZED_COMBO_BOX_TEXT))
+#define E_IS_ELLIPSIZED_COMBO_BOX_TEXT_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_ELLIPSIZED_COMBO_BOX_TEXT))
+#define E_ELLIPSIZED_COMBO_BOX_TEXT_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_ELLIPSIZED_COMBO_BOX_TEXT, EEllipsizedComboBoxTextClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EEllipsizedComboBoxText EEllipsizedComboBoxText;
+typedef struct _EEllipsizedComboBoxTextClass EEllipsizedComboBoxTextClass;
+typedef struct _EEllipsizedComboBoxTextPrivate EEllipsizedComboBoxTextPrivate;
+
+struct _EEllipsizedComboBoxText {
+       GtkComboBoxText parent;
+       EEllipsizedComboBoxTextPrivate *priv;
+};
+
+struct _EEllipsizedComboBoxTextClass {
+       GtkComboBoxTextClass parent_class;
+};
+
+GType          e_ellipsized_combo_box_text_get_type    (void) G_GNUC_CONST;
+GtkWidget *    e_ellipsized_combo_box_text_new         (gboolean has_entry);
+gint           e_ellipsized_combo_box_text_get_max_natural_width
+                                                       (EEllipsizedComboBoxText *combo_box);
+void           e_ellipsized_combo_box_text_set_max_natural_width
+                                                       (EEllipsizedComboBoxText *combo_box,
+                                                        gint max_natural_width);
+
+G_END_DECLS
+
+#endif /* E_ELLIPSIZED_COMBO_BOX_TEXT_H */
diff --git a/src/e-util/e-util.h b/src/e-util/e-util.h
index fa1243a79e..d6a50b85d6 100644
--- a/src/e-util/e-util.h
+++ b/src/e-util/e-util.h
@@ -98,6 +98,7 @@
 #include <e-util/e-destination-store.h>
 #include <e-util/e-dialog-utils.h>
 #include <e-util/e-dialog-widgets.h>
+#include <e-util/e-ellipsized-combo-box-text.h>
 #include <e-util/e-emoticon-action.h>
 #include <e-util/e-emoticon-chooser-menu.h>
 #include <e-util/e-emoticon-chooser.h>
diff --git a/src/modules/cal-config-local/CMakeLists.txt b/src/modules/cal-config-local/CMakeLists.txt
index 22f5ab54d0..dd6c74843d 100644
--- a/src/modules/cal-config-local/CMakeLists.txt
+++ b/src/modules/cal-config-local/CMakeLists.txt
@@ -1,4 +1,6 @@
-set(extra_deps)
+set(extra_deps
+       evolution-calendar
+)
 set(sources
        evolution-cal-config-local.c
 )
diff --git a/src/modules/cal-config-local/evolution-cal-config-local.c 
b/src/modules/cal-config-local/evolution-cal-config-local.c
index 9ed39040ef..827e1da8bd 100644
--- a/src/modules/cal-config-local/evolution-cal-config-local.c
+++ b/src/modules/cal-config-local/evolution-cal-config-local.c
@@ -22,7 +22,8 @@
 #include <libebackend/libebackend.h>
 #include <libedataserver/libedataserver.h>
 
-#include <e-util/e-util.h>
+#include "e-util/e-util.h"
+#include "calendar/gui/itip-utils.h"
 
 typedef ESourceConfigBackend ECalConfigLocal;
 typedef ESourceConfigBackendClass ECalConfigLocalClass;
@@ -47,6 +48,22 @@ G_DEFINE_DYNAMIC_TYPE (
        e_cal_config_local,
        E_TYPE_SOURCE_CONFIG_BACKEND)
 
+static void
+cal_config_local_fill_addresses (ESourceRegistry *registry,
+                                GtkComboBoxText *combo_box)
+{
+       gchar **address_strings;
+       gint ii;
+
+       address_strings = itip_get_user_identities (registry);
+
+       for (ii = 0; address_strings && address_strings[ii]; ii++) {
+               gtk_combo_box_text_append_text (combo_box, address_strings[ii]);
+       }
+
+       g_strfreev (address_strings);
+}
+
 static void
 cal_config_local_context_free (Context *context)
 {
@@ -146,98 +163,108 @@ cal_config_local_insert_widgets (ESourceConfigBackend *backend,
        source_is_builtin |= e_source_equal (scratch_source, builtin_source);
        g_object_unref (builtin_source);
 
-       if (source_is_builtin)
-               return;
-
-       context = g_slice_new (Context);
-
-       g_object_set_data_full (
-               G_OBJECT (backend), uid, context,
-               (GDestroyNotify) cal_config_local_context_free);
-
-       widget = gtk_check_button_new_with_label (
-               _("Use an existing iCalendar (ics) file"));
-       e_source_config_insert_widget (
-               config, scratch_source, NULL, widget);
-       context->custom_file_checkbox = g_object_ref (widget);
-       gtk_widget_show (widget);
-
-       g_signal_connect_swapped (
-               widget, "toggled",
-               G_CALLBACK (e_source_config_resize_window), config);
-
-       container = e_source_config_get_page (config, scratch_source);
-
-       /* Put some extra padding above and below the header. */
-       widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
-       gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 12, 6, 0, 0);
-       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
-       gtk_widget_show (widget);
-
-       e_binding_bind_property (
-               context->custom_file_checkbox, "active",
-               widget, "visible",
-               G_BINDING_SYNC_CREATE);
-
-       container = widget;
-
-       markup = g_markup_printf_escaped ("<b>%s</b>", _("iCalendar File"));
-       widget = gtk_label_new (markup);
-       gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
-       gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
-       gtk_container_add (GTK_CONTAINER (container), widget);
-       gtk_widget_show (widget);
-       g_free (markup);
-
-       filter = gtk_file_filter_new ();
-       gtk_file_filter_add_mime_type (filter, "text/calendar");
-
-       widget = gtk_file_chooser_button_new (
-               _("Choose an iCalendar file"), GTK_FILE_CHOOSER_ACTION_OPEN);
-       gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (widget), filter);
-       e_source_config_insert_widget (
-               config, scratch_source, _("File:"), widget);
-       context->custom_file_chooser = g_object_ref (widget);
-       gtk_widget_show (widget);
-
-       g_signal_connect (
-               widget, "file-set",
-               G_CALLBACK (cal_config_local_file_set_cb),
-               context->custom_file_checkbox);
+       extension_name = E_SOURCE_EXTENSION_LOCAL_BACKEND;
+       extension = e_source_get_extension (scratch_source, extension_name);
 
-       e_binding_bind_property (
-               context->custom_file_checkbox, "active",
-               widget, "visible",
-               G_BINDING_SYNC_CREATE);
+       if (!source_is_builtin) {
+               context = g_slice_new (Context);
+
+               g_object_set_data_full (
+                       G_OBJECT (backend), uid, context,
+                       (GDestroyNotify) cal_config_local_context_free);
+
+               widget = gtk_check_button_new_with_label (
+                       _("Use an existing iCalendar (ics) file"));
+               e_source_config_insert_widget (
+                       config, scratch_source, NULL, widget);
+               context->custom_file_checkbox = g_object_ref (widget);
+               gtk_widget_show (widget);
+
+               g_signal_connect_swapped (
+                       widget, "toggled",
+                       G_CALLBACK (e_source_config_resize_window), config);
+
+               container = e_source_config_get_page (config, scratch_source);
+
+               /* Put some extra padding above and below the header. */
+               widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
+               gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 12, 6, 0, 0);
+               gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+               gtk_widget_show (widget);
+
+               e_binding_bind_property (
+                       context->custom_file_checkbox, "active",
+                       widget, "visible",
+                       G_BINDING_SYNC_CREATE);
+
+               container = widget;
+
+               markup = g_markup_printf_escaped ("<b>%s</b>", _("iCalendar File"));
+               widget = gtk_label_new (markup);
+               gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
+               gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+               gtk_container_add (GTK_CONTAINER (container), widget);
+               gtk_widget_show (widget);
+               g_free (markup);
+
+               filter = gtk_file_filter_new ();
+               gtk_file_filter_add_mime_type (filter, "text/calendar");
+
+               widget = gtk_file_chooser_button_new (
+                       _("Choose an iCalendar file"), GTK_FILE_CHOOSER_ACTION_OPEN);
+               gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (widget), filter);
+               e_source_config_insert_widget (
+                       config, scratch_source, _("File:"), widget);
+               context->custom_file_chooser = g_object_ref (widget);
+               gtk_widget_show (widget);
+
+               g_signal_connect (
+                       widget, "file-set",
+                       G_CALLBACK (cal_config_local_file_set_cb),
+                       context->custom_file_checkbox);
+
+               e_binding_bind_property (
+                       context->custom_file_checkbox, "active",
+                       widget, "visible",
+                       G_BINDING_SYNC_CREATE);
+
+               widget = gtk_check_button_new_with_label (
+                       _("Allow Evolution to update the file"));
+               e_source_config_insert_widget (
+                       config, scratch_source, NULL, widget);
+               context->writable_checkbox = g_object_ref (widget);
+               gtk_widget_show (widget);
+
+               e_binding_bind_property (
+                       context->custom_file_checkbox, "active",
+                       widget, "visible",
+                       G_BINDING_SYNC_CREATE);
+
+               e_binding_bind_property_full (
+                       extension, "custom-file",
+                       context->custom_file_checkbox, "active",
+                       G_BINDING_BIDIRECTIONAL |
+                       G_BINDING_SYNC_CREATE,
+                       cal_config_local_custom_file_to_active,
+                       cal_config_local_active_to_custom_file,
+                       context, (GDestroyNotify) NULL);
+
+               e_binding_bind_property (
+                       extension, "writable",
+                       context->writable_checkbox, "active",
+                       G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+       }
 
-       widget = gtk_check_button_new_with_label (
-               _("Allow Evolution to update the file"));
-       e_source_config_insert_widget (
-               config, scratch_source, NULL, widget);
-       context->writable_checkbox = g_object_ref (widget);
+       widget = e_ellipsized_combo_box_text_new (TRUE);
+       cal_config_local_fill_addresses (registry, GTK_COMBO_BOX_TEXT (widget));
+       e_source_config_insert_widget (config, scratch_source, _("Email:"), widget);
        gtk_widget_show (widget);
 
-       e_binding_bind_property (
-               context->custom_file_checkbox, "active",
-               widget, "visible",
-               G_BINDING_SYNC_CREATE);
-
-       extension_name = E_SOURCE_EXTENSION_LOCAL_BACKEND;
-       extension = e_source_get_extension (scratch_source, extension_name);
-
-       e_binding_bind_property_full (
-               extension, "custom-file",
-               context->custom_file_checkbox, "active",
+       e_binding_bind_object_text_property (
+               extension, "email-address",
+               gtk_bin_get_child (GTK_BIN (widget)), "text",
                G_BINDING_BIDIRECTIONAL |
-               G_BINDING_SYNC_CREATE,
-               cal_config_local_custom_file_to_active,
-               cal_config_local_active_to_custom_file,
-               context, (GDestroyNotify) NULL);
-
-       e_binding_bind_property (
-               extension, "writable",
-               context->writable_checkbox, "active",
-               G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+               G_BINDING_SYNC_CREATE);
 }
 
 static gboolean


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