[gtranslator] added deletion from translation memory. added popup menu to translation memory ui.
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtranslator] added deletion from translation memory. added popup menu to translation memory ui.
- Date: Sun, 9 May 2010 17:36:32 +0000 (UTC)
commit 14e05041ea83fe7920bd3a8cb0fc73bd0cd02c3d
Author: Andrey Kutejko <andy128k gmail com>
Date: Sun May 9 20:14:44 2010 +0300
added deletion from translation memory.
added popup menu to translation memory ui.
src/translation-memory/gda/gtr-gda.c | 53 +++-
src/translation-memory/gtr-translation-memory-ui.c | 341 +++++++++++++++++---
src/translation-memory/gtr-translation-memory.c | 28 ++
src/translation-memory/gtr-translation-memory.h | 16 +-
4 files changed, 380 insertions(+), 58 deletions(-)
---
diff --git a/src/translation-memory/gda/gtr-gda.c b/src/translation-memory/gda/gtr-gda.c
index a7f202f..0dc5309 100644
--- a/src/translation-memory/gda/gtr-gda.c
+++ b/src/translation-memory/gda/gtr-gda.c
@@ -61,6 +61,8 @@ struct _GtrGdaPrivate
GdaStatement *stmt_insert_link;
GdaStatement *stmt_insert_trans;
+ GdaStatement *stmt_delete_trans;
+
guint max_omits;
guint max_delta;
gint max_items;
@@ -400,6 +402,31 @@ gtr_gda_store_list (GtrTranslationMemory * tm, GList * msgs)
}
static void
+gtr_gda_remove (GtrTranslationMemory *tm,
+ const gchar *original,
+ const gchar *translation)
+{
+ GtrGda *self = GTR_GDA (tm);
+ gchar *norm_translation;
+ GdaSet *params;
+
+ norm_translation = g_utf8_normalize (translation, -1,
+ G_NORMALIZE_DEFAULT);
+
+ params = gda_set_new_inline (2,
+ "original", G_TYPE_STRING, original,
+ "value", G_TYPE_STRING, norm_translation);
+
+ gda_connection_statement_execute_non_select (self->priv->db,
+ self->priv->stmt_delete_trans,
+ params,
+ NULL, NULL);
+
+ g_object_unref (params);
+ g_free (norm_translation);
+}
+
+static void
free_match (GtrTranslationMemoryMatch *match, gpointer dummy)
{
g_free (match->match);
@@ -468,7 +495,7 @@ gtr_gda_get_lookup_statement (GtrGda *self, guint word_count, GError **error)
gchar *query;
stmt = GDA_STATEMENT (g_hash_table_lookup (self->priv->lookup_query_cache,
- GUINT_TO_POINTER (word_count)));
+ GUINT_TO_POINTER (word_count)));
if (stmt)
return stmt;
@@ -481,8 +508,8 @@ gtr_gda_get_lookup_statement (GtrGda *self, guint word_count, GError **error)
g_free (query);
g_hash_table_insert (self->priv->lookup_query_cache,
- GUINT_TO_POINTER (word_count),
- stmt);
+ GUINT_TO_POINTER (word_count),
+ stmt);
return stmt;
}
@@ -649,6 +676,7 @@ gtr_translation_memory_iface_init (GtrTranslationMemoryIface * iface)
{
iface->store = gtr_gda_store;
iface->store_list = gtr_gda_store_list;
+ iface->remove = gtr_gda_remove;
iface->lookup = gtr_gda_lookup;
iface->set_max_omits = gtr_gda_set_max_omits;
iface->set_max_delta = gtr_gda_set_max_delta;
@@ -794,14 +822,21 @@ gtr_gda_init (GtrGda * self)
"values "
"(##orig_id::int, ##value::string)");
+ self->priv->stmt_delete_trans =
+ prepare_statement (self->priv->parser,
+ "delete from TRANS "
+ "where ORIG_ID= "
+ "(select ID from ORIG where VALUE=##original::string) "
+ "and VALUE=##value::string");
+
self->priv->max_omits = 0;
self->priv->max_delta = 0;
self->priv->max_items = 0;
self->priv->lookup_query_cache = g_hash_table_new_full (g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
+ g_direct_equal,
+ NULL,
+ g_object_unref);
}
static void
@@ -857,6 +892,12 @@ gtr_gda_dispose (GObject * object)
self->priv->stmt_insert_trans = NULL;
}
+ if (self->priv->stmt_delete_trans != NULL)
+ {
+ g_object_unref (self->priv->stmt_delete_trans);
+ self->priv->stmt_delete_trans = NULL;
+ }
+
if (self->priv->parser != NULL)
{
g_object_unref (self->priv->parser);
diff --git a/src/translation-memory/gtr-translation-memory-ui.c b/src/translation-memory/gtr-translation-memory-ui.c
index 8083d02..69de7f7 100644
--- a/src/translation-memory/gtr-translation-memory-ui.c
+++ b/src/translation-memory/gtr-translation-memory-ui.c
@@ -1,16 +1,16 @@
/*
- * Copyright (C) 2008 Igalia
- *
+ * Copyright (C) 2008 Igalia
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* 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 General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
@@ -28,6 +28,7 @@
#include "gtr-translation-memory.h"
#include "gtr-translation-memory-ui.h"
#include "gtr-tab.h"
+#include "gtr-utils.h"
#include "gtr-window.h"
#include <string.h>
@@ -39,43 +40,47 @@
#define MAX_ELEMENTS 10
-#define GTR_TRANSLATION_MEMORY_UI_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ( \
- (object), \
- GTR_TYPE_TRANSLATION_MEMORY_UI, \
- GtrTranslationMemoryUiPrivate))
+#define GTR_TRANSLATION_MEMORY_UI_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
+ GTR_TYPE_TRANSLATION_MEMORY_UI, \
+ GtrTranslationMemoryUiPrivate))
G_DEFINE_TYPE (GtrTranslationMemoryUi,
- gtr_translation_memory_ui, GTK_TYPE_SCROLLED_WINDOW)
- struct _GtrTranslationMemoryUiPrivate
- {
- GtkWidget *tree_view;
- GtrTab *tab;
-
- gchar **tm_list;
- };
-
- enum
- {
- SHORTCUT_COLUMN,
- LEVEL_COLUMN,
- STRING_COLUMN,
- N_COLUMNS
- };
-
- static void
- tree_view_size_cb (GtkWidget * widget,
- GtkAllocation * allocation, gpointer user_data);
-
- static void
- on_activate_item_cb (GtkMenuItem * menuitem,
- GtrTranslationMemoryUi * tm_ui)
+ gtr_translation_memory_ui,
+ GTK_TYPE_SCROLLED_WINDOW)
+
+struct _GtrTranslationMemoryUiPrivate
+{
+ GtkWidget *tree_view;
+ GtrTab *tab;
+
+ gchar **tm_list;
+
+ GtkWidget *popup_menu;
+ GtrMsg *msg;
+};
+
+enum
+ {
+ SHORTCUT_COLUMN,
+ LEVEL_COLUMN,
+ STRING_COLUMN,
+ N_COLUMNS
+ };
+
+static void
+tree_view_size_cb (GtkWidget * widget,
+ GtkAllocation * allocation,
+ gpointer user_data);
+
+static void
+choose_translation (GtrTranslationMemoryUi *tm_ui, const gchar *translation)
{
GtrView *view;
GtkTextBuffer *buffer;
GtrPo *po;
GList *current_msg = NULL;
GtrMsg *msg;
- gint index;
GtrWindow *window;
window = gtr_application_get_active_window (GTR_APP);
@@ -83,25 +88,34 @@ G_DEFINE_TYPE (GtrTranslationMemoryUi,
view = gtr_window_get_active_view (window);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
- /* Possible this hack is not going to work with all languages neither, we
- are supposing the integer at the end of the string */
- index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem), "option"));
-
po = gtr_tab_get_po (tm_ui->priv->tab);
current_msg = gtr_po_get_current_message (po);
msg = GTR_MSG (current_msg->data);
- gtr_msg_set_msgstr (msg, tm_ui->priv->tm_list[index - 1]);
+ gtr_msg_set_msgstr (msg, translation);
gtk_text_buffer_begin_user_action (buffer);
- gtk_text_buffer_set_text (buffer, tm_ui->priv->tm_list[index - 1], -1);
+ gtk_text_buffer_set_text (buffer, translation, -1);
gtk_text_buffer_end_user_action (buffer);
gtr_po_set_state (po, GTR_PO_STATE_MODIFIED);
}
static void
+on_activate_item_cb (GtkMenuItem * menuitem,
+ GtrTranslationMemoryUi * tm_ui)
+{
+ gint index;
+
+ /* Possible this hack is not going to work with all languages neither, we
+ are supposing the integer at the end of the string */
+ index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem), "option"));
+
+ choose_translation (tm_ui, tm_ui->priv->tm_list[index - 1]);
+}
+
+static void
free_list (gpointer data, gpointer useless)
{
GtrTranslationMemoryMatch *match = (GtrTranslationMemoryMatch *) data;
@@ -142,6 +156,11 @@ showed_message_cb (GtrTab * tab, GtrMsg * msg, GtrTranslationMemoryUi * tm_ui)
"size_allocate",
G_CALLBACK (tree_view_size_cb), tm_ui->priv->tree_view);
+ g_object_ref (msg);
+ if (tm_ui->priv->msg)
+ g_object_unref (tm_ui->priv->msg);
+ tm_ui->priv->msg = msg;
+
msgid = gtr_msg_get_msgid (msg);
tm =
@@ -178,12 +197,11 @@ showed_message_cb (GtrTab * tab, GtrMsg * msg, GtrTranslationMemoryUi * tm_ui)
g_list_free (renderers_list);
gtk_list_store_append (model, &iter);
- gtk_list_store_set (model,
- &iter,
- SHORTCUT_COLUMN,
- GDK_0 + k,
- STRING_COLUMN,
- match->match, LEVEL_COLUMN, match->level, -1);
+ gtk_list_store_set (model, &iter,
+ SHORTCUT_COLUMN, GDK_0 + k,
+ STRING_COLUMN, match->match,
+ LEVEL_COLUMN, match->level,
+ -1);
i++;
k++;
if (k == MAX_ELEMENTS)
@@ -242,8 +260,180 @@ showed_message_cb (GtrTab * tab, GtrMsg * msg, GtrTranslationMemoryUi * tm_ui)
}
static void
+tree_view_row_activated (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ GtrTranslationMemoryUi *tm_ui)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar *translation;
+
+ model = gtk_tree_view_get_model (tree_view);
+
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ return;
+
+ gtk_tree_model_get (model, &iter,
+ STRING_COLUMN, &translation,
+ -1);
+
+ choose_translation (tm_ui, translation);
+
+ g_free (translation);
+}
+
+static void
+popup_menu_translation_activate (GtkMenuItem *menuitem,
+ GtrTranslationMemoryUi *tm_ui)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar *translation;
+
+ selection =
+ gtk_tree_view_get_selection (GTK_TREE_VIEW (tm_ui->priv->tree_view));
+ if (!gtk_tree_selection_get_selected (selection,
+ &model,
+ &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter,
+ STRING_COLUMN, &translation,
+ -1);
+
+ choose_translation (tm_ui, translation);
+
+ g_free (translation);
+}
+
+static void
+popup_menu_remove_from_memory (GtkMenuItem *menuitem,
+ GtrTranslationMemoryUi *tm_ui)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtrTranslationMemory *tm;
+ gint level;
+ const gchar *original;
+ gchar *translation;
+
+ selection =
+ gtk_tree_view_get_selection (GTK_TREE_VIEW (tm_ui->priv->tree_view));
+ if (!gtk_tree_selection_get_selected (selection,
+ &model,
+ &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter,
+ LEVEL_COLUMN, &level,
+ -1);
+
+ if (level != 100)
+ return;
+
+ gtk_tree_model_get (model, &iter,
+ STRING_COLUMN, &translation,
+ -1);
+
+ tm =
+ GTR_TRANSLATION_MEMORY (gtr_application_get_translation_memory (GTR_APP));
+
+ original = gtr_msg_get_msgid (tm_ui->priv->msg);
+ gtr_translation_memory_remove (tm, original, translation);
+
+ g_free (translation);
+
+ /* update list */
+ showed_message_cb (tm_ui->priv->tab, tm_ui->priv->msg, tm_ui);
+}
+
+static GtkWidget *
+create_tree_popup_menu (GtrTranslationMemoryUi *self)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean remove_available = FALSE;
+ GtkWidget *menu;
+ GtkWidget *item;
+ GtkWidget *image;
+
+ selection =
+ gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->tree_view));
+ if (gtk_tree_selection_get_selected (selection,
+ &model,
+ &iter))
+ {
+ gint level;
+
+ gtk_tree_model_get (model, &iter,
+ LEVEL_COLUMN, &level,
+ -1);
+
+ remove_available = (level == 100);
+ }
+
+ menu = gtk_menu_new ();
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Use this translation"));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (popup_menu_translation_activate), self);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_image_menu_item_new_with_mnemonic (_("_Remove"));
+ image = gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ g_signal_connect (item, "activate",
+ G_CALLBACK (popup_menu_remove_from_memory), self);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_set_sensitive (item, remove_available);
+
+ gtk_widget_show_all (menu);
+
+ return menu;
+}
+
+static void
+tree_popup_menu_detach (GtrTranslationMemoryUi *self, GtkMenu * menu)
+{
+ self->priv->popup_menu = NULL;
+}
+
+static void
+gtr_translation_memory_ui_show_menu (GtrTranslationMemoryUi *self,
+ GdkEventButton * event)
+{
+ if (self->priv->popup_menu)
+ gtk_widget_destroy (self->priv->popup_menu);
+
+ self->priv->popup_menu = create_tree_popup_menu (self);
+
+ gtk_menu_attach_to_widget (GTK_MENU (self->priv->popup_menu),
+ GTK_WIDGET (self),
+ (GtkMenuDetachFunc) tree_popup_menu_detach);
+
+ if (event != NULL)
+ {
+ gtk_menu_popup (GTK_MENU (self->priv->popup_menu), NULL, NULL,
+ NULL, NULL,
+ event->button, event->time);
+ }
+ else
+ {
+ gtk_menu_popup (GTK_MENU (self->priv->popup_menu), NULL, NULL,
+ gtr_utils_menu_position_under_tree_view,
+ self->priv->tree_view,
+ 0, gtk_get_current_event_time ());
+ }
+}
+
+static void
tree_view_size_cb (GtkWidget * widget,
- GtkAllocation * allocation, gpointer user_data)
+ GtkAllocation * allocation,
+ gpointer user_data)
{
GtkTreeView *treeview;
GtkTreeViewColumn *column;
@@ -262,6 +452,33 @@ tree_view_size_cb (GtkWidget * widget,
g_list_free (renderers_list);
}
+static gboolean
+tree_view_button_press_event (GtkTreeView *tree,
+ GdkEventButton *event,
+ GtrTranslationMemoryUi *tm_ui)
+{
+ GtkTreePath *path;
+
+ if (GDK_BUTTON_PRESS != event->type || 3 != event->button)
+ return FALSE;
+
+ if (!gtk_tree_view_get_path_at_pos (tree, event->x, event->y,
+ &path, NULL, NULL, NULL))
+ return FALSE;
+
+ gtk_widget_grab_focus (GTK_WIDGET (tree));
+ gtk_tree_view_set_cursor (tree, path, NULL, FALSE);
+
+ gtr_translation_memory_ui_show_menu (tm_ui, event);
+ return TRUE;
+}
+
+static gboolean
+tree_view_popup_menu (GtkTreeView *tree, GtrTranslationMemoryUi *tm_ui)
+{
+ gtr_translation_memory_ui_show_menu (tm_ui, NULL);
+ return TRUE;
+}
static void
gtr_translation_memory_ui_draw (GtrTranslationMemoryUi * tm_ui)
@@ -310,9 +527,20 @@ gtr_translation_memory_ui_draw (GtrTranslationMemoryUi * tm_ui)
g_object_set (string_renderer,
"ypad", 0,
"xpad", 5,
- "yalign", 0.0, "wrap-mode", PANGO_WRAP_WORD_CHAR, NULL);
+ "yalign", 0.0,
+ "wrap-mode", PANGO_WRAP_WORD_CHAR,
+ NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), string);
+
+ g_signal_connect (priv->tree_view, "button-press-event",
+ G_CALLBACK (tree_view_button_press_event), tm_ui);
+
+ g_signal_connect (priv->tree_view, "popup-menu",
+ G_CALLBACK (tree_view_popup_menu), tm_ui);
+
+ g_signal_connect (priv->tree_view, "row-activated",
+ G_CALLBACK (tree_view_row_activated), tm_ui);
}
static void
@@ -320,11 +548,27 @@ gtr_translation_memory_ui_init (GtrTranslationMemoryUi * tm_ui)
{
tm_ui->priv = GTR_TRANSLATION_MEMORY_UI_GET_PRIVATE (tm_ui);
tm_ui->priv->tm_list = NULL;
+ tm_ui->priv->popup_menu = NULL;
+ tm_ui->priv->msg = NULL;
gtr_translation_memory_ui_draw (tm_ui);
}
static void
+gtr_translation_memory_ui_dispose (GObject * object)
+{
+ GtrTranslationMemoryUi *tm_ui = GTR_TRANSLATION_MEMORY_UI (object);
+
+ if (tm_ui->priv->msg)
+ {
+ g_object_unref (tm_ui->priv->msg);
+ tm_ui->priv->msg = NULL;
+ }
+
+ G_OBJECT_CLASS (gtr_translation_memory_ui_parent_class)->dispose (object);
+}
+
+static void
gtr_translation_memory_ui_finalize (GObject * object)
{
GtrTranslationMemoryUi *tm_ui = GTR_TRANSLATION_MEMORY_UI (object);
@@ -335,12 +579,13 @@ gtr_translation_memory_ui_finalize (GObject * object)
}
static void
- gtr_translation_memory_ui_class_init (GtrTranslationMemoryUiClass * klass)
+gtr_translation_memory_ui_class_init (GtrTranslationMemoryUiClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (GtrTranslationMemoryUiPrivate));
+ object_class->dispose = gtr_translation_memory_ui_dispose;
object_class->finalize = gtr_translation_memory_ui_finalize;
}
diff --git a/src/translation-memory/gtr-translation-memory.c b/src/translation-memory/gtr-translation-memory.c
index 0c9b363..f8b1706 100644
--- a/src/translation-memory/gtr-translation-memory.c
+++ b/src/translation-memory/gtr-translation-memory.c
@@ -76,6 +76,33 @@ gtr_translation_memory_store_list_default (GtrTranslationMemory * obj,
}
/**
+ * gtr_translation_memory_remove:
+ * @obj: a #GtrTranslationMemory
+ * @original: the original message.
+ * @translation: the translation to remove.
+ *
+ * Removes @translation of @original from translation memory.
+ */
+void
+gtr_translation_memory_remove (GtrTranslationMemory * obj,
+ const gchar * original,
+ const gchar * translation)
+{
+ g_return_if_fail (GTR_IS_TRANSLATION_MEMORY (obj));
+ return GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->remove (obj,
+ original,
+ translation);
+}
+
+/* Default implementation */
+static void
+gtr_translation_memory_remove_default (GtrTranslationMemory * obj,
+ const gchar * original,
+ const gchar * translation)
+{
+}
+
+/**
* gtr_translation_memory_lookup:
* @obj: a #GtrTranslationMemory
* @phrase: the unstranslated text to search for translations.
@@ -170,6 +197,7 @@ gtr_translation_memory_base_init (GtrTranslationMemoryIface * klass)
klass->store = gtr_translation_memory_store_default;
klass->store_list = gtr_translation_memory_store_list_default;
+ klass->remove = gtr_translation_memory_remove_default;
klass->lookup = gtr_translation_memory_lookup_default;
klass->set_max_omits = gtr_translation_memory_set_max_omits_default;
klass->set_max_delta = gtr_translation_memory_set_max_delta_default;
diff --git a/src/translation-memory/gtr-translation-memory.h b/src/translation-memory/gtr-translation-memory.h
index 9cc063c..b111621 100644
--- a/src/translation-memory/gtr-translation-memory.h
+++ b/src/translation-memory/gtr-translation-memory.h
@@ -1,16 +1,16 @@
/*
* Copyright (C) 2008 Ignacio Casal Quinteiro <nacho resa gmail com>
- *
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* 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 General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -32,9 +32,12 @@ typedef struct _GtrTranslationMemoryIface GtrTranslationMemoryIface;
struct _GtrTranslationMemoryIface
{
GTypeInterface g_iface;
-
+
gboolean (*store) (GtrTranslationMemory * obj, GtrMsg * msg);
gboolean (*store_list) (GtrTranslationMemory * obj, GList * msgs);
+ void (*remove) (GtrTranslationMemory * obj,
+ const gchar * original,
+ const gchar *translation);
GList *(*lookup) (GtrTranslationMemory * obj, const gchar * phrase);
void (*set_max_omits) (GtrTranslationMemory * obj, gsize omits);
@@ -58,6 +61,11 @@ gtr_translation_memory_store (GtrTranslationMemory * obj, GtrMsg * msg);
gboolean
gtr_translation_memory_store_list (GtrTranslationMemory * obj, GList * msg);
+void
+gtr_translation_memory_remove (GtrTranslationMemory * obj,
+ const gchar * original,
+ const gchar * translation);
+
GList *
gtr_translation_memory_lookup (GtrTranslationMemory * obj,
const gchar * phrase);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]