[gtranslator] Translation memory from plugins to src
- From: Daniel Garcia Moreno <danigm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtranslator] Translation memory from plugins to src
- Date: Wed, 12 Sep 2018 11:55:13 +0000 (UTC)
commit ec1e6417d4dca188559a9038dfcea7c321330886
Author: Daniel García Moreno <danigm wadobo com>
Date: Fri Sep 7 14:03:21 2018 +0200
Translation memory from plugins to src
build-aux/flatpak/org.gnome.Gtranslator.json | 54 +-
meson.build | 2 +
src/gtr-context.c | 30 +
src/gtr-context.ui | 16 +-
src/gtr-tab.ui | 2 +
src/meson.build | 2 +
src/translation-memory/gda/gda-utils.c | 152 ++++
src/translation-memory/gda/gda-utils.h | 31 +
src/translation-memory/gda/gtr-gda.c | 999 +++++++++++++++++++++
src/translation-memory/gda/gtr-gda.h | 58 ++
src/translation-memory/gda/meson.build | 4 +
.../gtr-translation-memory-dialog.c | 375 ++++++++
.../gtr-translation-memory-dialog.h | 56 ++
.../gtr-translation-memory-dialog.ui | 322 +++++++
src/translation-memory/gtr-translation-memory-ui.c | 495 ++++++++++
src/translation-memory/gtr-translation-memory-ui.h | 62 ++
.../gtr-translation-memory-utils.c | 96 ++
.../gtr-translation-memory-utils.h | 33 +
src/translation-memory/gtr-translation-memory.c | 208 +++++
.../gtr-translation-memory.gresource.xml | 6 +
src/translation-memory/gtr-translation-memory.h | 80 ++
src/translation-memory/meson.build | 36 +
...lator.plugins.translation-memory.gschema.xml.in | 43 +
23 files changed, 3133 insertions(+), 29 deletions(-)
---
diff --git a/build-aux/flatpak/org.gnome.Gtranslator.json b/build-aux/flatpak/org.gnome.Gtranslator.json
index 8574a5d2..87e15584 100644
--- a/build-aux/flatpak/org.gnome.Gtranslator.json
+++ b/build-aux/flatpak/org.gnome.Gtranslator.json
@@ -52,32 +52,32 @@
]
},
{
- "name" : "gdl",
- "sources" : [
- {
- "type" : "git",
- "url" : "https://gitlab.gnome.org/GNOME/gdl.git"
- }
- ]
- },
- {
- "name" : "libgda",
- "buildsystem" : "meson",
- "sources" : [
- {
- "type" : "git",
- "url" : "https://gitlab.gnome.org/GNOME/libgda.git"
- }
- ]
- },
- {
- "name" : "libpeas",
- "sources" : [
- {
- "type" : "git",
- "url" : "https://gitlab.gnome.org/GNOME/libpeas.git"
- }
- ]
+ "name": "libgda",
+ "config-opts": [
+ "--enable-json=yes",
+ "--enable-system-sqlite=yes",
+ /* FIXME */
+ "--enable-introspection=no"
+ ],
+ "sources": [
+ {
+ "type": "archive",
+ "url": "http://ftp.gnome.org/pub/GNOME/sources/libgda/5.2/libgda-5.2.4.tar.xz",
+ "sha256": "2cee38dd583ccbaa5bdf6c01ca5f88cc08758b9b144938a51a478eb2684b765e"
+ }
+ ],
+ "cleanup": [
+ "/include",
+ "/lib/*.a",
+ "/lib/*.la",
+ "/lib/pkgconfig",
+ "/man",
+ "/share/aclocal",
+ "/share/doc",
+ "/share/gtk-doc",
+ "/share/man",
+ "/share/pkgconfig"
+ ]
},
{
"name" : "gettext",
@@ -103,4 +103,4 @@
]
}
]
-}
\ No newline at end of file
+}
diff --git a/meson.build b/meson.build
index 81f2ad39..b2df339f 100644
--- a/meson.build
+++ b/meson.build
@@ -113,12 +113,14 @@ add_project_arguments(common_flags, language: 'c')
gtk_dep = dependency('gtk+-3.0', version: '>= 3.22.20')
glib_dep = dependency('glib-2.0', version: '>=2.36.0')
+gda_dep = dependency('libgda-5.0')
gtranslator_deps = [
iso_codes_dep,
po_dep,
gtk_dep,
glib_dep,
+ gda_dep,
dependency('libxml-2.0', version: '>=2.4.12'),
dependency('gthread-2.0', version: '>=2.13.0'),
dependency('gio-2.0', version: '>=2.36.0'),
diff --git a/src/gtr-context.c b/src/gtr-context.c
index 2b953ac1..519621c6 100644
--- a/src/gtr-context.c
+++ b/src/gtr-context.c
@@ -22,6 +22,9 @@
#include "gtr-context.h"
#include "gtr-tab.h"
#include "gtr-debug.h"
+#include "translation-memory/gtr-translation-memory.h"
+#include "translation-memory/gtr-translation-memory-ui.h"
+#include "translation-memory/gda/gtr-gda.h"
#include <glib.h>
#include <glib/gi18n.h>
@@ -34,6 +37,7 @@ typedef struct
GtkWidget *context;
GtkWidget *button_box;
GtkWidget *button;
+ GtkWidget *translation_memory_box;
GdkCursor *hand_cursor;
GdkCursor *regular_cursor;
@@ -41,6 +45,11 @@ typedef struct
GtrTab *tab;
GtrMsg *current_msg;
+
+ // translation memory
+ GSettings *tm_settings;
+ GtrTranslationMemory *translation_memory;
+ GtkWidget *translation_memory_ui;
} GtrContextPanelPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (GtrContextPanel, gtr_context_panel, GTK_TYPE_BOX)
@@ -378,6 +387,24 @@ gtr_context_panel_init (GtrContextPanel *panel)
g_signal_connect (priv->button, "clicked",
G_CALLBACK (on_done_button_clicked), panel);
+
+ priv->tm_settings = g_settings_new ("org.gnome.gtranslator.plugins.translation-memory");
+ priv->translation_memory = GTR_TRANSLATION_MEMORY (gtr_gda_new());
+ gtr_translation_memory_set_max_omits (priv->translation_memory,
+ g_settings_get_int (priv->tm_settings,
+ "max-missing-words"));
+ gtr_translation_memory_set_max_delta (priv->translation_memory,
+ g_settings_get_int (priv->tm_settings,
+ "max-length-diff"));
+ gtr_translation_memory_set_max_items (priv->translation_memory, 10);
+
+ priv->translation_memory_ui = gtr_translation_memory_ui_new (GTK_WIDGET (priv->tab),
+ priv->translation_memory);
+ gtk_widget_show (priv->translation_memory_ui);
+ gtk_widget_set_size_request (priv->translation_memory_ui, 300, 400);
+ gtk_box_pack_start (GTK_BOX (priv->translation_memory_box),
+ priv->translation_memory_ui,
+ FALSE, FALSE, 0);
}
static void
@@ -455,6 +482,8 @@ gtr_context_panel_dispose (GObject *object)
g_clear_object (&priv->hand_cursor);
g_clear_object (&priv->regular_cursor);
+ g_clear_object (&priv->translation_memory);
+ g_clear_object (&priv->tm_settings);
G_OBJECT_CLASS (gtr_context_panel_parent_class)->dispose (object);
}
@@ -497,6 +526,7 @@ gtr_context_panel_class_init (GtrContextPanelClass * klass)
gtk_widget_class_bind_template_child_private (widget_class, GtrContextPanel, context);
gtk_widget_class_bind_template_child_private (widget_class, GtrContextPanel, button_box);
gtk_widget_class_bind_template_child_private (widget_class, GtrContextPanel, button);
+ gtk_widget_class_bind_template_child_private (widget_class, GtrContextPanel, translation_memory_box);
}
/**
diff --git a/src/gtr-context.ui b/src/gtr-context.ui
index 3e1dfdfe..f11fb69e 100644
--- a/src/gtr-context.ui
+++ b/src/gtr-context.ui
@@ -7,6 +7,18 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="translation_memory_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
<child>
<object class="GtkScrolledWindow" id="sw">
<property name="visible">True</property>
@@ -25,7 +37,7 @@
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">0</property>
+ <property name="position">1</property>
</packing>
</child>
<child>
@@ -51,7 +63,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">1</property>
+ <property name="position">2</property>
</packing>
</child>
</template>
diff --git a/src/gtr-tab.ui b/src/gtr-tab.ui
index ca2f81a9..98b989d7 100644
--- a/src/gtr-tab.ui
+++ b/src/gtr-tab.ui
@@ -137,6 +137,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tab">GtrTab</property>
+ <property name="width_request">400</property>
</object>
<packing>
<property name="expand">False</property>
@@ -154,3 +155,4 @@
</template>
</interface>
+
diff --git a/src/meson.build b/src/meson.build
index 97f3a345..ed7d7a1c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -115,9 +115,11 @@ sources += gnome.compile_resources(
incs = [
top_inc,
include_directories('toolbareditor'),
+ include_directories('translation-memory'),
]
subdir('toolbareditor')
+subdir('translation-memory')
###############
diff --git a/src/translation-memory/gda/gda-utils.c b/src/translation-memory/gda/gda-utils.c
new file mode 100644
index 00000000..57fd124c
--- /dev/null
+++ b/src/translation-memory/gda/gda-utils.c
@@ -0,0 +1,152 @@
+/*
+ * (C) 2001 Fatih Demir <kabalak kabalak net>
+ * 2012 Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * gtranslator 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gtranslator 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/>.
+ *
+ * Authors:
+ * Ignacio Casal Quinteiro <icq gnome org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gda-utils.h"
+
+#include <string.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+
+static const gchar *badwords[] = {
+ "a",
+ //"all",
+ "an",
+ //"are",
+ //"can",
+ //"for",
+ //"from",
+ "have",
+ //"it",
+ //"may",
+ //"not",
+ "of",
+ //"that",
+ "the",
+ //"this",
+ //"was",
+ "will",
+ //"with",
+ //"you",
+ //"your",
+ NULL
+};
+
+static gboolean
+check_good_word (const gchar * word, gchar ** badwords)
+{
+ gboolean check = TRUE;
+ gchar *lower = g_utf8_strdown (word, -1);
+ gint i = 0;
+
+ while (badwords[i] != NULL)
+ {
+ gchar *lower_collate = g_utf8_collate_key (lower, -1);
+
+ if (strcmp (lower_collate, badwords[i]) == 0)
+ {
+ check = FALSE;
+ g_free (lower_collate);
+ break;
+ }
+ i++;
+ g_free (lower_collate);
+ }
+ return check;
+}
+
+
+/**
+ * gtr_gda_utils_split_string_in_words:
+ * @string: the text to process
+ *
+ * Process a text and split it in words using pango.
+ *
+ * Returns: an array of words of the processed text
+ */
+gchar **
+gtr_gda_utils_split_string_in_words (const gchar * string)
+{
+ PangoLanguage *lang = pango_language_from_string ("en");
+ PangoLogAttr *attrs;
+ GPtrArray *array;
+ gint char_len;
+ gint i = 0;
+ gchar *s;
+ gchar *start = NULL;
+ static gchar **badwords_collate = NULL;
+
+ if (badwords_collate == NULL)
+ {
+ gint words_size = g_strv_length ((gchar **) badwords);
+ gint x = 0;
+
+ badwords_collate = g_new0 (gchar *, words_size + 1);
+
+ while (badwords[x] != NULL)
+ {
+ badwords_collate[x] = g_utf8_collate_key (badwords[x], -1);
+ x++;
+ }
+ badwords_collate[x] = NULL;
+ }
+
+ char_len = g_utf8_strlen (string, -1);
+ attrs = g_new (PangoLogAttr, char_len + 1);
+
+ pango_get_log_attrs (string,
+ strlen (string), -1, lang, attrs, char_len + 1);
+
+ array = g_ptr_array_new ();
+
+ s = (gchar *) string;
+ while (i <= char_len)
+ {
+ gchar *end;
+
+ if (attrs[i].is_word_start)
+ start = s;
+ if (attrs[i].is_word_end)
+ {
+ gchar *word;
+
+ end = s;
+ word = g_strndup (start, end - start);
+
+ if (check_good_word (word, badwords_collate))
+ g_ptr_array_add (array, word);
+ }
+
+ i++;
+ s = g_utf8_next_char (s);
+ }
+
+ g_free (attrs);
+ g_ptr_array_add (array, NULL);
+
+ return (gchar **) g_ptr_array_free (array, FALSE);
+}
+
diff --git a/src/translation-memory/gda/gda-utils.h b/src/translation-memory/gda/gda-utils.h
new file mode 100644
index 00000000..7036e7e6
--- /dev/null
+++ b/src/translation-memory/gda/gda-utils.h
@@ -0,0 +1,31 @@
+/*
+ * (C) 2001 Fatih Demir <kabalak kabalak net>
+ * 2012 Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * gtranslator 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gtranslator 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/>.
+ *
+ * Authors:
+ * Fatih Demir <kabalak kabalak net>
+ * Ignacio Casal Quinteiro <icq gnome org>
+ */
+
+#ifndef GDA_UTILS_H
+#define GDA_UTILS_H 1
+
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+gchar **gtr_gda_utils_split_string_in_words (const gchar *string);
+
+#endif
diff --git a/src/translation-memory/gda/gtr-gda.c b/src/translation-memory/gda/gtr-gda.c
new file mode 100644
index 00000000..0c140e07
--- /dev/null
+++ b/src/translation-memory/gda/gtr-gda.c
@@ -0,0 +1,999 @@
+/*
+ * Copyright (C) 2010 Andrey Kutejko <andy128k 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libgda.h>
+#include <sql-parser/gda-sql-parser.h>
+#include "gtr-gda.h"
+#include "gtr-translation-memory.h"
+#include "gtr-dirs.h"
+#include "gda-utils.h"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <string.h>
+
+#define GTR_GDA_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
+ GTR_TYPE_GDA, \
+ GtrGdaPrivate))
+
+static void
+gtr_translation_memory_iface_init (GtrTranslationMemoryInterface * iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtrGda,
+ gtr_gda,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTR_TYPE_TRANSLATION_MEMORY,
+ gtr_translation_memory_iface_init))
+
+struct _GtrGdaPrivate
+{
+ GdaConnection *db;
+
+ GdaSqlParser *parser;
+
+ /* prepared statements */
+ GdaStatement *stmt_find_orig;
+ GdaStatement *stmt_select_trans;
+ GdaStatement *stmt_select_word;
+ GdaStatement *stmt_find_trans;
+
+ GdaStatement *stmt_insert_orig;
+ GdaStatement *stmt_insert_word;
+ GdaStatement *stmt_insert_link;
+ GdaStatement *stmt_insert_trans;
+
+ GdaStatement *stmt_delete_trans;
+
+ guint max_omits;
+ guint max_delta;
+ gint max_items;
+
+ GHashTable *lookup_query_cache;
+};
+
+static gint
+select_integer (GdaConnection *db,
+ GdaStatement *stmt,
+ GdaSet *params,
+ GError **error)
+{
+ GdaDataModel *model;
+ GError *inner_error;
+ gint result = 0;
+
+ inner_error = NULL;
+ model = gda_connection_statement_execute_select (db, stmt, params,
+ &inner_error);
+ g_object_unref (params);
+
+ if (!model)
+ {
+ g_propagate_error (error, inner_error);
+ return 0;
+ }
+
+ if (gda_data_model_get_n_rows (model) > 0)
+ {
+ const GValue * val;
+
+ inner_error = NULL;
+ val = gda_data_model_get_typed_value_at (model,
+ 0, 0,
+ G_TYPE_INT,
+ FALSE,
+ &inner_error);
+ if (val)
+ result = g_value_get_int (val);
+ else
+ g_propagate_error (error, inner_error);
+ }
+
+ g_object_unref (model);
+
+ return result;
+}
+
+static gint
+insert_row (GdaConnection *db,
+ GdaStatement *stmt,
+ GdaSet *params,
+ GError **error)
+{
+ GdaSet *last_row;
+ GError *inner_error;
+ const GValue * val;
+ gint result = 0;
+
+ inner_error = NULL;
+ if (-1 == gda_connection_statement_execute_non_select (db,
+ stmt,
+ params,
+ &last_row,
+ &inner_error))
+ {
+ g_object_unref (params);
+ g_propagate_error (error, inner_error);
+ return 0;
+ }
+ g_object_unref (params);
+
+ g_return_val_if_fail (last_row != NULL, 0);
+
+ val = gda_set_get_holder_value (last_row, "+0");
+ if (val)
+ result = g_value_get_int (val);
+
+ g_object_unref (last_row);
+
+ return result;
+}
+
+static int
+string_comparator (const void *s1, const void *s2)
+{
+ return strcmp (*(const gchar **) s1, *(const gchar **) s2);
+}
+
+static gchar **
+gtr_gda_split_string_in_words (const gchar *phrase)
+{
+ gchar **words = gtr_gda_utils_split_string_in_words (phrase);
+ gsize count = g_strv_length (words);
+ gint w;
+ gint r;
+
+ if (count <= 1)
+ return words;
+
+ qsort (words, count, sizeof (gchar *), string_comparator);
+
+ w = 1;
+ r = 1;
+ for (; r < count; ++r)
+ {
+ if (0 == strcmp (words[r], words[w-1]))
+ {
+ g_free (words[r]);
+ }
+ else
+ {
+ words[w] = words[r];
+ ++w;
+ }
+ }
+ words[w] = NULL;
+
+ return words;
+}
+
+static void
+gtr_gda_words_append (GtrGda *self,
+ const gchar * word,
+ gint orig_id,
+ GError **error)
+{
+ GError *inner_error;
+ gint word_id = 0;
+
+ /* look for word */
+ {
+ inner_error = NULL;
+ word_id = select_integer (self->priv->db,
+ self->priv->stmt_select_word,
+ gda_set_new_inline (1,
+ "value", G_TYPE_STRING,
+ word),
+ &inner_error);
+ if (inner_error)
+ {
+ g_propagate_error (error, inner_error);
+ return;
+ }
+ }
+
+ if (word_id == 0)
+ {
+ inner_error = NULL;
+ word_id = insert_row (self->priv->db,
+ self->priv->stmt_insert_word,
+ gda_set_new_inline (1,
+ "value", G_TYPE_STRING, word),
+ &inner_error);
+ if (inner_error)
+ {
+ g_propagate_error (error, inner_error);
+ return;
+ }
+ }
+
+ /* insert link */
+ {
+ GdaSet *params;
+
+ params = gda_set_new_inline (2,
+ "word_id", G_TYPE_INT, word_id,
+ "orig_id", G_TYPE_INT, orig_id);
+
+ inner_error = NULL;
+ if (-1 == gda_connection_statement_execute_non_select (self->priv->db,
+ self->priv->stmt_insert_link,
+ params,
+ NULL,
+ &inner_error))
+ g_propagate_error (error, inner_error);
+
+ g_object_unref (params);
+ }
+}
+
+static gboolean
+gtr_gda_store_impl (GtrGda *self,
+ const gchar * original,
+ const gchar * translation,
+ GError **error)
+{
+ gint orig_id;
+ gboolean found_translation = FALSE;
+ gchar **words = NULL;
+ GError *inner_error;
+
+ inner_error = NULL;
+ orig_id = select_integer (self->priv->db,
+ self->priv->stmt_find_orig,
+ gda_set_new_inline (1,
+ "original", G_TYPE_STRING,
+ original),
+ &inner_error);
+ if (inner_error)
+ {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ if (orig_id == 0)
+ {
+ gsize sz, i;
+
+ words = gtr_gda_split_string_in_words (original);
+ sz = g_strv_length (words);
+
+ inner_error = NULL;
+ orig_id = insert_row (self->priv->db,
+ self->priv->stmt_insert_orig,
+ gda_set_new_inline (2,
+ "original", G_TYPE_STRING,
+ original,
+ "sentence_size", G_TYPE_INT,
+ (gint) sz),
+ &inner_error);
+ if (inner_error)
+ goto error;
+
+ /* insert words */
+ for (i = 0; i < sz; i++)
+ {
+ inner_error = NULL;
+ gtr_gda_words_append (self, words[i], orig_id, &inner_error);
+ if (inner_error)
+ goto error;
+ }
+
+ g_strfreev (words);
+ }
+ else
+ {
+ inner_error = NULL;
+ found_translation = select_integer (self->priv->db,
+ self->priv->stmt_find_trans,
+ gda_set_new_inline (2,
+ "orig_id",
+ G_TYPE_INT,
+ orig_id,
+ "value",
+ G_TYPE_STRING,
+ translation),
+ &inner_error);
+ if (inner_error)
+ goto error;
+ }
+
+ if (!found_translation)
+ {
+ inner_error = NULL;
+ insert_row (self->priv->db,
+ self->priv->stmt_insert_trans,
+ gda_set_new_inline (2,
+ "orig_id", G_TYPE_INT,
+ orig_id,
+ "value", G_TYPE_STRING,
+ translation),
+ &inner_error);
+ if (inner_error)
+ goto error;
+ }
+
+ return TRUE;
+
+ error:
+ g_strfreev (words);
+ g_propagate_error (error, inner_error);
+ return FALSE;
+}
+
+static gboolean
+gtr_gda_store (GtrTranslationMemory * tm, GtrMsg * msg)
+{
+ GtrGda *self = GTR_GDA (tm);
+ gboolean result;
+ GError *error;
+
+ g_return_val_if_fail (GTR_IS_GDA (self), FALSE);
+
+ error = NULL;
+ if (!gda_connection_begin_transaction (self->priv->db,
+ NULL,
+ GDA_TRANSACTION_ISOLATION_READ_COMMITTED,
+ &error))
+ {
+ g_warning ("starting transaction failed: %s", error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ error = NULL;
+ result = gtr_gda_store_impl (self,
+ gtr_msg_get_msgid (msg),
+ gtr_msg_get_msgstr (msg),
+ &error);
+
+ if (error)
+ {
+ g_warning ("storing message failed: %s", error->message);
+ g_error_free (error);
+ }
+
+ if (result)
+ gda_connection_commit_transaction (self->priv->db, NULL, NULL);
+ else
+ gda_connection_rollback_transaction (self->priv->db, NULL, NULL);
+
+ return result;
+}
+
+static gboolean
+gtr_gda_store_list (GtrTranslationMemory * tm, GList * msgs)
+{
+ GtrGda *self = GTR_GDA (tm);
+ gboolean result = TRUE;
+ GList *l;
+ GError *error;
+
+ g_return_val_if_fail (GTR_IS_GDA (self), FALSE);
+
+ error = NULL;
+ if (!gda_connection_begin_transaction (self->priv->db,
+ NULL,
+ GDA_TRANSACTION_ISOLATION_READ_COMMITTED,
+ &error))
+ {
+ g_warning ("starting transaction failed: %s", error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ for (l = msgs; l; l = g_list_next (l))
+ {
+ GtrMsg *msg = GTR_MSG (l->data);
+
+ if (!gtr_msg_is_translated (msg) || gtr_msg_is_fuzzy (msg))
+ continue;
+
+ error = NULL;
+ result = gtr_gda_store_impl (self,
+ gtr_msg_get_msgid (msg),
+ gtr_msg_get_msgstr (msg),
+ &error);
+ if (!result)
+ {
+ g_warning ("storing message failed: %s", error->message);
+ g_error_free (error);
+ break;
+ }
+ }
+
+ if (result)
+ gda_connection_commit_transaction (self->priv->db, NULL, NULL);
+ else
+ gda_connection_rollback_transaction (self->priv->db, NULL, NULL);
+
+ return result;
+}
+
+static void
+gtr_gda_remove (GtrTranslationMemory *tm,
+ gint translation_id)
+{
+ GtrGda *self = GTR_GDA (tm);
+ GdaSet *params;
+ GError *error;
+
+ params = gda_set_new_inline (1,
+ "id_trans",
+ G_TYPE_INT,
+ translation_id);
+
+ error = NULL;
+ gda_connection_statement_execute_non_select (self->priv->db,
+ self->priv->stmt_delete_trans,
+ params,
+ NULL,
+ &error);
+ if (error)
+ {
+ g_warning ("removing translation failed: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (params);
+}
+
+static void
+free_match (gpointer data)
+{
+ GtrTranslationMemoryMatch *match = (GtrTranslationMemoryMatch *) data;
+
+ g_free (match->match);
+ g_slice_free (GtrTranslationMemoryMatch, match);
+}
+
+static gchar*
+build_lookup_query (GtrGda *self, guint word_count)
+{
+ GString * query = g_string_sized_new (1024);
+ guint i;
+
+ g_string_append_printf (query,
+ "select "
+ " TRANS.VALUE, "
+ " 100 SCORE, "
+ " TRANS.ID "
+ "from "
+ " TRANS, ORIG "
+ "where ORIG.ID = TRANS.ORIG_ID "
+ " and ORIG.VALUE = ##phrase::string "
+ "union "
+ "select "
+ " TRANS.VALUE, "
+ " SC SCORE, "
+ " TRANS.ID "
+ "from TRANS, "
+ " (select "
+ " ORIG.ID ORID, "
+ " cast(count(1) * count(1) * 100 "
+ " / (%d * ORIG.SENTENCE_SIZE + 1) "
+ " as integer) SC "
+ " from "
+ " WORD, WORD_ORIG_LINK, ORIG "
+ " where WORD.ID = WORD_ORIG_LINK.WORD_ID "
+ " and ORIG.ID = WORD_ORIG_LINK.ORIG_ID "
+ " and ORIG.VALUE <> ##phrase::string "
+ " and ORIG.SENTENCE_SIZE between %u and %u "
+ " and WORD.VALUE in (",
+ word_count,
+ word_count,
+ word_count + self->priv->max_delta);
+
+ for (i = 0; i < word_count; ++i)
+ {
+ g_string_append_printf (query, "##word%d::string", i);
+ if (i != word_count - 1)
+ g_string_append (query, ", ");
+ }
+
+ g_string_append_printf (query,
+ ") "
+ " group by ORIG.ID "
+ " having count(1) >= %d) "
+ "where ORID = TRANS.ORIG_ID "
+ "order by SCORE desc "
+ "limit %d",
+ word_count - self->priv->max_omits,
+ self->priv->max_items);
+
+ return g_string_free (query, FALSE);
+}
+
+static GdaStatement *
+gtr_gda_get_lookup_statement (GtrGda *self, guint word_count, GError **error)
+{
+ GdaStatement *stmt;
+ gchar *query;
+
+ stmt = GDA_STATEMENT (g_hash_table_lookup (self->priv->lookup_query_cache,
+ GUINT_TO_POINTER (word_count)));
+
+ if (stmt)
+ return stmt;
+
+ query = build_lookup_query (self, word_count);
+ stmt = gda_sql_parser_parse_string (self->priv->parser,
+ query,
+ NULL,
+ error);
+ g_free (query);
+
+ g_hash_table_insert (self->priv->lookup_query_cache,
+ GUINT_TO_POINTER (word_count),
+ stmt);
+
+ return stmt;
+}
+
+static GList *
+gtr_gda_lookup (GtrTranslationMemory * tm, const gchar * phrase)
+{
+ GtrGda *self = GTR_GDA (tm);
+ gchar **words = NULL;
+ guint cnt = 0;
+ GList *matches = NULL;
+ GError *inner_error;
+ GdaStatement *stmt = NULL;
+ GdaSet *params = NULL;
+ GdaDataModel *model = NULL;
+ gint i;
+
+ g_return_val_if_fail (GTR_IS_GDA (self), NULL);
+
+ if (!gda_connection_begin_transaction (self->priv->db,
+ NULL,
+ GDA_TRANSACTION_ISOLATION_READ_COMMITTED,
+ NULL))
+ return NULL;
+
+ words = gtr_gda_split_string_in_words (phrase);
+ cnt = g_strv_length (words);
+
+ inner_error = NULL;
+ stmt = gtr_gda_get_lookup_statement (self, cnt, &inner_error);
+ if (inner_error)
+ goto end;
+
+ inner_error = NULL;
+ if (!gda_statement_get_parameters (stmt, ¶ms, &inner_error))
+ goto end;
+
+ inner_error = NULL;
+ gda_set_set_holder_value (params,
+ &inner_error,
+ "phrase", phrase);
+ if (inner_error)
+ goto end;
+
+ {
+ gchar word_id[25];
+ for (i = 0; i < cnt; i++)
+ {
+ sprintf (word_id, "word%d", i);
+
+ inner_error = NULL;
+ gda_set_set_holder_value (params,
+ &inner_error,
+ word_id, words[i]);
+ if (inner_error)
+ goto end;
+ }
+ }
+
+ inner_error = NULL;
+ model = gda_connection_statement_execute_select (self->priv->db,
+ stmt,
+ params,
+ &inner_error);
+ if (!model)
+ goto end;
+
+ {
+ gint count = gda_data_model_get_n_rows (model);
+ for (i = 0; i < count; ++i)
+ {
+ const GValue * val;
+ gchar *suggestion;
+ gint score;
+ gint id;
+ GtrTranslationMemoryMatch *match;
+
+ inner_error = NULL;
+ val = gda_data_model_get_typed_value_at (model,
+ 0, i,
+ G_TYPE_STRING,
+ FALSE,
+ &inner_error);
+ if (!val)
+ goto end;
+
+ suggestion = g_value_dup_string (val);
+
+ inner_error = NULL;
+ val = gda_data_model_get_typed_value_at (model,
+ 1, i,
+ G_TYPE_INT,
+ FALSE,
+ &inner_error);
+ if (!val)
+ {
+ g_free (suggestion);
+ goto end;
+ }
+
+ score = g_value_get_int (val);
+
+ inner_error = NULL;
+ val = gda_data_model_get_typed_value_at (model,
+ 2, i,
+ G_TYPE_INT,
+ FALSE,
+ &inner_error);
+ if (!val)
+ {
+ g_free (suggestion);
+ goto end;
+ }
+
+ id = g_value_get_int (val);
+
+ match = g_slice_new (GtrTranslationMemoryMatch);
+ match->match = suggestion;
+ match->level = score;
+ match->id = id;
+
+ matches = g_list_prepend (matches, match);
+ }
+ }
+
+ end:
+
+ if (model)
+ g_object_unref (model);
+ if (params)
+ g_object_unref (params);
+
+ gda_connection_rollback_transaction (self->priv->db, NULL, NULL);
+
+ if (inner_error)
+ {
+ g_list_free_full (matches, free_match);
+
+ g_warning ("%s\n", inner_error->message);
+
+ g_error_free (inner_error);
+
+ return NULL;
+ }
+
+ matches = g_list_reverse (matches);
+ return matches;
+}
+
+static void
+gtr_gda_set_max_omits (GtrTranslationMemory * tm, gsize omits)
+{
+ GtrGda *self = GTR_GDA (tm);
+
+ self->priv->max_omits = omits;
+ g_hash_table_remove_all (self->priv->lookup_query_cache);
+}
+
+static void
+gtr_gda_set_max_delta (GtrTranslationMemory * tm, gsize delta)
+{
+ GtrGda *self = GTR_GDA (tm);
+
+ self->priv->max_delta = delta;
+ g_hash_table_remove_all (self->priv->lookup_query_cache);
+}
+
+static void
+gtr_gda_set_max_items (GtrTranslationMemory * tm, gint items)
+{
+ GtrGda *self = GTR_GDA (tm);
+
+ self->priv->max_items = items;
+ g_hash_table_remove_all (self->priv->lookup_query_cache);
+}
+
+static void
+gtr_translation_memory_iface_init (GtrTranslationMemoryInterface * 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;
+ iface->set_max_items = gtr_gda_set_max_items;
+}
+
+static GdaStatement *
+prepare_statement(GdaSqlParser *parser, const gchar *query)
+{
+ GError *error = NULL;
+ GdaStatement *statement = gda_sql_parser_parse_string (parser,
+ query,
+ NULL,
+ &error);
+
+ if (error)
+ {
+ g_error ("gtr-gda.c: prepare_statement: "
+ "gda_sql_parser_parse_string failed.\n"
+ "query: %s\n"
+ "error message: %s\n",
+ query,
+ error->message);
+ }
+ return statement;
+}
+
+static void
+gtr_gda_init (GtrGda * self)
+{
+ gchar *connection_string;
+ GError *error = NULL;
+
+ self->priv = GTR_GDA_GET_PRIVATE (self);
+
+ gda_init ();
+
+ {
+ const gchar *config_dir;
+ gchar *encoded_config_dir;
+
+ config_dir = gtr_dirs_get_user_config_dir ();
+ encoded_config_dir = gda_rfc1738_encode (config_dir);
+
+ connection_string = g_strdup_printf ("DB_DIR=%s;"
+ "DB_NAME=translation-memory",
+ encoded_config_dir);
+
+ g_free (encoded_config_dir);
+ }
+
+ self->priv->db = gda_connection_open_from_string ("Sqlite",
+ connection_string,
+ NULL,
+ GDA_CONNECTION_OPTIONS_NONE,
+ &error);
+ if (error)
+ {
+ g_warning ("Error creating database: %s", error->message);
+ g_error_free (error);
+ }
+
+ gda_connection_execute_non_select_command (self->priv->db,
+ "create table WORD ("
+ "ID integer primary key autoincrement,"
+ "VALUE text unique)",
+ NULL);
+
+ gda_connection_execute_non_select_command (self->priv->db,
+ "create table WORD_ORIG_LINK ("
+ "WORD_ID integer,"
+ "ORIG_ID integer,"
+ "primary key (WORD_ID, ORIG_ID))",
+ NULL);
+
+ gda_connection_execute_non_select_command (self->priv->db,
+ "create table ORIG ("
+ "ID integer primary key autoincrement,"
+ "VALUE text unique,"
+ "SENTENCE_SIZE integer)",
+ NULL);
+
+ gda_connection_execute_non_select_command (self->priv->db,
+ "create table TRANS ("
+ "ID integer primary key autoincrement,"
+ "ORIG_ID integer,"
+ "VALUE text)",
+ NULL);
+
+ gda_connection_execute_non_select_command (self->priv->db,
+ "create index "
+ "if not exists IDX_TRANS_ORIG_ID "
+ "on TRANS (ORIG_ID)",
+ NULL);
+
+ /* prepare statements */
+
+ self->priv->parser = gda_connection_create_parser (self->priv->db);
+ if (self->priv->parser == NULL)
+ self->priv->parser = gda_sql_parser_new ();
+
+ self->priv->stmt_find_orig =
+ prepare_statement (self->priv->parser,
+ "select ID from ORIG "
+ "where VALUE=##original::string");
+
+ self->priv->stmt_select_word =
+ prepare_statement (self->priv->parser,
+ "select ID from WORD "
+ "where VALUE=##value::string");
+
+ self->priv->stmt_select_trans =
+ prepare_statement (self->priv->parser,
+ "select VALUE from TRANS "
+ "where ORIG_ID=##orig_id::int");
+
+ self->priv->stmt_find_trans =
+ prepare_statement (self->priv->parser,
+ "select ID from TRANS "
+ "where ORIG_ID=##orig_id::int "
+ "and VALUE=##value::string");
+
+ self->priv->stmt_insert_orig =
+ prepare_statement (self->priv->parser,
+ "insert into "
+ "ORIG (VALUE, SENTENCE_SIZE) "
+ "values "
+ "(##original::string, ##sentence_size::int)");
+
+ self->priv->stmt_insert_word =
+ prepare_statement (self->priv->parser,
+ "insert into "
+ "WORD (VALUE) "
+ "values "
+ "(##value::string)");
+
+ self->priv->stmt_insert_link =
+ prepare_statement (self->priv->parser,
+ "insert into "
+ "WORD_ORIG_LINK (WORD_ID, ORIG_ID) "
+ "values "
+ "(##word_id::int, ##orig_id::int)");
+
+ self->priv->stmt_insert_trans =
+ prepare_statement (self->priv->parser,
+ "insert into "
+ "TRANS (ORIG_ID, VALUE) "
+ "values "
+ "(##orig_id::int, ##value::string)");
+
+ self->priv->stmt_delete_trans =
+ prepare_statement (self->priv->parser,
+ "delete from TRANS "
+ "where id = ##id_trans::int");
+
+ 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);
+}
+
+static void
+gtr_gda_dispose (GObject * object)
+{
+ GtrGda *self = GTR_GDA (object);
+
+ if (self->priv->stmt_find_orig != NULL)
+ {
+ g_object_unref (self->priv->stmt_find_orig);
+ self->priv->stmt_find_orig = NULL;
+ }
+
+ if (self->priv->stmt_select_trans != NULL)
+ {
+ g_object_unref (self->priv->stmt_select_trans);
+ self->priv->stmt_select_trans = NULL;
+ }
+
+ if (self->priv->stmt_find_trans != NULL)
+ {
+ g_object_unref (self->priv->stmt_find_trans);
+ self->priv->stmt_find_trans = NULL;
+ }
+
+ if (self->priv->stmt_select_word != NULL)
+ {
+ g_object_unref (self->priv->stmt_select_word);
+ self->priv->stmt_select_word = NULL;
+ }
+
+ if (self->priv->stmt_insert_orig != NULL)
+ {
+ g_object_unref (self->priv->stmt_insert_orig);
+ self->priv->stmt_insert_orig = NULL;
+ }
+
+ if (self->priv->stmt_insert_word != NULL)
+ {
+ g_object_unref (self->priv->stmt_insert_word);
+ self->priv->stmt_insert_word = NULL;
+ }
+
+ if (self->priv->stmt_insert_link != NULL)
+ {
+ g_object_unref (self->priv->stmt_insert_link);
+ self->priv->stmt_insert_link = NULL;
+ }
+
+ if (self->priv->stmt_insert_trans != NULL)
+ {
+ g_object_unref (self->priv->stmt_insert_trans);
+ 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);
+ self->priv->parser = NULL;
+ }
+
+ if (self->priv->db != NULL)
+ {
+ g_object_unref (self->priv->db);
+ self->priv->db = NULL;
+ }
+
+ if (self->priv->lookup_query_cache != NULL)
+ {
+ g_hash_table_unref (self->priv->lookup_query_cache);
+ self->priv->lookup_query_cache = NULL;
+ }
+
+ G_OBJECT_CLASS (gtr_gda_parent_class)->dispose (object);
+}
+
+static void
+gtr_gda_class_init (GtrGdaClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GtrGdaPrivate));
+ object_class->dispose = gtr_gda_dispose;
+}
+
+/**
+ * gtr_gda_new:
+ *
+ * Creates a new #GtrGda object.
+ *
+ * Returns: a new #GtrGda object
+ */
+GtrGda *
+gtr_gda_new ()
+{
+ GtrGda *gda;
+
+ gda = g_object_new (GTR_TYPE_GDA, NULL);
+
+ return gda;
+}
+
diff --git a/src/translation-memory/gda/gtr-gda.h b/src/translation-memory/gda/gtr-gda.h
new file mode 100644
index 00000000..a2f0e91b
--- /dev/null
+++ b/src/translation-memory/gda/gtr-gda.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Andrey Kutejko <andy128k 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/>.
+ */
+
+#ifndef __GDA_BACKEND_H__
+#define __GDA_BACKEND_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTR_TYPE_GDA (gtr_gda_get_type ())
+#define GTR_GDA(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTR_TYPE_GDA, GtrGda))
+#define GTR_GDA_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GTR_TYPE_GDA, GtrGdaClass))
+#define GTR_IS_GDA(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTR_TYPE_GDA))
+#define GTR_IS_GDA_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTR_TYPE_GDA))
+#define GTR_GDA_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTR_TYPE_GDA, GtrGdaClass))
+
+typedef struct _GtrGdaPrivate GtrGdaPrivate;
+typedef struct _GtrGda GtrGda;
+typedef struct _GtrGdaClass GtrGdaClass;
+
+struct _GtrGda
+{
+ GObject parent_instance;
+
+ /*< private > */
+ GtrGdaPrivate *priv;
+};
+
+struct _GtrGdaClass
+{
+ GObjectClass parent_class;
+};
+
+GType gtr_gda_get_type (void) G_GNUC_CONST;
+
+GType gtr_gda_register_type (GTypeModule *module);
+
+GtrGda *gtr_gda_new (void);
+
+G_END_DECLS
+#endif /* __GDA_BACKEND_H__ */
diff --git a/src/translation-memory/gda/meson.build b/src/translation-memory/gda/meson.build
new file mode 100644
index 00000000..c44d486e
--- /dev/null
+++ b/src/translation-memory/gda/meson.build
@@ -0,0 +1,4 @@
+sources += files(
+ 'gda-utils.c',
+ 'gtr-gda.c',
+)
diff --git a/src/translation-memory/gtr-translation-memory-dialog.c
b/src/translation-memory/gtr-translation-memory-dialog.c
new file mode 100644
index 00000000..26edca70
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-dialog.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2012 Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * 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/>.
+ */
+
+#include "gtr-translation-memory-dialog.h"
+#include "gtr-profile-manager.h"
+#include "gtr-translation-memory-utils.h"
+#include "gtr-po.h"
+
+#include <glib/gi18n.h>
+
+
+#define GTR_TRANSLATION_MEMORY_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object),
GTR_TYPE_TRANSLATION_MEMORY_DIALOG, GtrTranslationMemoryDialogPrivate))
+
+struct _GtrTranslationMemoryDialogPrivate
+{
+ GSettings *tm_settings;
+
+ GtkWidget *directory_entry;
+ GtkWidget *search_button;
+ GtkWidget *add_database_button;
+ GtkWidget *add_database_progressbar;
+ GtkWidget *tm_lang_entry;
+ GtkWidget *use_lang_profile_in_tm;
+
+ GtrTranslationMemory *translation_memory;
+};
+
+G_DEFINE_TYPE (GtrTranslationMemoryDialog, gtr_translation_memory_dialog, GTK_TYPE_DIALOG)
+
+static void
+gtr_translation_memory_dialog_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (gtr_translation_memory_dialog_parent_class)->finalize (object);
+}
+
+static void
+gtr_translation_memory_dialog_dispose (GObject *object)
+{
+ GtrTranslationMemoryDialogPrivate *priv = GTR_TRANSLATION_MEMORY_DIALOG (object)->priv;
+
+ g_clear_object (&priv->tm_settings);
+
+ G_OBJECT_CLASS (gtr_translation_memory_dialog_parent_class)->dispose (object);
+}
+
+static void
+gtr_translation_memory_dialog_class_init (GtrTranslationMemoryDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtr_translation_memory_dialog_finalize;
+ object_class->dispose = gtr_translation_memory_dialog_dispose;
+
+ g_type_class_add_private (object_class, sizeof (GtrTranslationMemoryDialogPrivate));
+}
+
+/***************Translation Memory pages****************/
+static void
+response_filechooser_cb (GtkDialog *dialog,
+ gint response_id,
+ GtrTranslationMemoryDialog *dlg)
+{
+ if (response_id == GTK_RESPONSE_YES)
+ {
+ gchar *filename;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ gtk_entry_set_text (GTK_ENTRY (dlg->priv->directory_entry),
+ filename);
+ g_settings_set_string (dlg->priv->tm_settings,
+ "po-directory",
+ filename);
+ g_free (filename);
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+on_search_button_clicked (GtkButton *button,
+ GtrTranslationMemoryDialog *dlg)
+{
+ GtkWidget *filechooser;
+
+ filechooser = gtk_file_chooser_dialog_new ("Select PO directory",
+ GTK_WINDOW (dlg),
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_YES, NULL);
+
+ g_signal_connect (GTK_DIALOG (filechooser), "response",
+ G_CALLBACK (response_filechooser_cb), dlg);
+
+ gtk_widget_show (filechooser);
+}
+
+typedef struct _IdleData
+{
+ GSList *list;
+ GtkProgressBar *progress;
+ GtrTranslationMemory *tm;
+ GtkWindow *parent;
+} IdleData;
+
+static gboolean
+add_to_database (gpointer data_pointer)
+{
+ IdleData *data = (IdleData *) data_pointer;
+ static GSList *l = NULL;
+ gdouble percentage;
+
+ if (l == NULL)
+ l = data->list;
+ else
+ l = g_slist_next (l);
+
+ if (l)
+ {
+ GList *msg_list = NULL;
+ GFile *location;
+ GError *error = NULL;
+ GtrPo *po;
+
+ po = gtr_po_new ();
+ location = (GFile *) l->data;
+
+ gtr_po_parse (po, location, &error);
+ if (error)
+ return TRUE;
+
+ msg_list = gtr_po_get_messages (po);
+
+ gtr_translation_memory_store_list (data->tm, msg_list);
+
+ g_object_unref (po);
+ }
+ else
+ {
+ GtkWidget *dialog;
+ gchar *markup;
+
+ gtk_progress_bar_set_fraction (data->progress, 1.0);
+
+ dialog = gtk_message_dialog_new (data->parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE, NULL);
+
+ markup =
+ g_strdup_printf("<span weight=\"bold\" size=\"large\">%s</span>",
+ _("Strings added to database"));
+ gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), markup);
+ g_free(markup);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_widget_show (dialog);
+
+ return FALSE;
+ }
+
+ percentage =
+ (gdouble) g_slist_position (data->list,
+ l) / (gdouble) g_slist_length (data->list);
+
+ /*
+ * Set the progress only if the values are reasonable.
+ */
+ if (percentage > 0.0 && percentage < 1.0)
+ {
+ /* Set the progressbar status. */
+ gtk_progress_bar_set_fraction (data->progress, percentage);
+ }
+
+ return TRUE;
+}
+
+static void
+destroy_idle_data (gpointer data)
+{
+ IdleData *d = (IdleData *) data;
+
+ gtk_widget_hide (GTK_WIDGET (d->progress));
+
+ g_slist_free_full (d->list, g_object_unref);
+ g_free (d);
+}
+
+static void
+on_add_database_button_clicked (GtkButton *button,
+ GtrTranslationMemoryDialog *dlg)
+{
+ GFile *dir;
+ gchar *dir_name;
+ IdleData *data;
+
+ dir_name = g_settings_get_string (dlg->priv->tm_settings,
+ "po-directory");
+
+ /* If dir name is empty, show a warning message */
+ if (*dir_name == '\0')
+ {
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new (GTK_WINDOW (dlg),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE,
+ _("Please specify a valid path to build the translation memory"));
+
+ gtk_widget_show (dialog);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ g_free (dir_name);
+ return;
+ }
+
+ dir = g_file_new_for_path (dir_name);
+ g_free (dir_name);
+
+ data = g_new0 (IdleData, 1);
+ data->list = NULL;
+
+ if (g_settings_get_boolean (dlg->priv->tm_settings,
+ "restrict-to-filename"))
+ {
+ gchar *restriction;
+
+ restriction = g_settings_get_string (dlg->priv->tm_settings,
+ "filename-restriction");
+ gtr_scan_dir (dir, &data->list, restriction);
+ g_free (restriction);
+ }
+ else
+ gtr_scan_dir (dir, &data->list, NULL);
+
+ data->tm = dlg->priv->translation_memory;
+ data->progress = GTK_PROGRESS_BAR (dlg->priv->add_database_progressbar);
+ data->parent = GTK_WINDOW (dlg);
+
+ gtk_widget_show (dlg->priv->add_database_progressbar);
+ g_idle_add_full (G_PRIORITY_HIGH_IDLE + 30,
+ (GSourceFunc) add_to_database,
+ data, (GDestroyNotify) destroy_idle_data);
+
+ g_object_unref (dir);
+}
+
+static void
+gtr_translation_memory_dialog_init (GtrTranslationMemoryDialog *dlg)
+{
+ GtrTranslationMemoryDialogPrivate *priv;
+ GtkWidget *action_area;
+ GtkWidget *content_area;
+ GtkBuilder *builder;
+ GtkWidget *content;
+ GtrProfileManager *prof_manager;
+ GtrProfile *profile;
+ const gchar *language_code;
+ gchar *filename = NULL;
+ gchar *root_objects[] = {
+ "translation-memory-box",
+ NULL
+ };
+
+ dlg->priv = GTR_TRANSLATION_MEMORY_DIALOG_GET_PRIVATE (dlg);
+ priv = dlg->priv;
+
+ priv->tm_settings = g_settings_new ("org.gnome.gtranslator.plugins.translation-memory");
+
+ gtk_dialog_add_buttons (GTK_DIALOG (dlg),
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_CLOSE,
+ NULL);
+
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Gtranslator Translation Memory Manager"));
+ gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
+
+ action_area = gtk_dialog_get_action_area (GTK_DIALOG (dlg));
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (dlg));
+
+ /* HIG defaults */
+ gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
+ gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
+ gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
+ gtk_box_set_spacing (GTK_BOX (action_area), 4);
+
+ g_signal_connect (dlg, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ builder = gtk_builder_new ();
+ gtk_builder_add_objects_from_resource (builder,
"/org/gnome/gtranslator/plugins/translation-memory/ui/gtr-translation-memory-dialog.ui", root_objects, NULL);
+ content = GTK_WIDGET (gtk_builder_get_object (builder, "translation-memory-box"));
+ g_object_ref (content);
+ priv->directory_entry = GTK_WIDGET (gtk_builder_get_object (builder, "directory-entry"));
+ priv->search_button = GTK_WIDGET (gtk_builder_get_object (builder, "search-button"));
+ priv->add_database_button = GTK_WIDGET (gtk_builder_get_object (builder, "add-database-button"));
+ priv->add_database_progressbar = GTK_WIDGET (gtk_builder_get_object (builder, "add-database-progressbar"));
+ priv->use_lang_profile_in_tm = GTK_WIDGET (gtk_builder_get_object (builder, "use-lang-profile-in-tm"));
+ priv->tm_lang_entry = GTK_WIDGET (gtk_builder_get_object (builder, "tm-lang-entry"));
+ g_object_unref (builder);
+
+ gtk_box_pack_start (GTK_BOX (content_area), content, TRUE, TRUE, 0);
+ g_object_unref (content);
+
+ prof_manager = gtr_profile_manager_get_default ();
+ profile = gtr_profile_manager_get_active_profile (prof_manager);
+
+ if (profile != NULL)
+ {
+ language_code = gtr_profile_get_language_code (profile);
+ filename = g_strconcat (language_code, ".po", NULL);
+
+ gtk_entry_set_text (GTK_ENTRY (priv->tm_lang_entry), filename);
+ }
+ g_object_unref (prof_manager);
+
+ if (filename != NULL)
+ g_settings_set_string (priv->tm_settings,
+ "filename-restriction",
+ filename);
+
+ g_free (filename);
+
+ g_settings_bind (priv->tm_settings,
+ "restrict-to-filename",
+ priv->use_lang_profile_in_tm,
+ "active",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (priv->tm_settings,
+ "po-directory",
+ priv->directory_entry,
+ "text",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (priv->tm_settings,
+ "filename-restriction",
+ priv->tm_lang_entry,
+ "text",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+
+ g_signal_connect (GTK_BUTTON (priv->search_button), "clicked",
+ G_CALLBACK (on_search_button_clicked), dlg);
+
+ g_signal_connect (GTK_BUTTON (priv->add_database_button), "clicked",
+ G_CALLBACK (on_add_database_button_clicked), dlg);
+}
+
+GtkWidget *
+gtr_translation_memory_dialog_new (GtrTranslationMemory *translation_memory)
+{
+ GtrTranslationMemoryDialog *dlg;
+
+ dlg = GTR_TRANSLATION_MEMORY_DIALOG (g_object_new (GTR_TYPE_TRANSLATION_MEMORY_DIALOG, NULL));
+
+ /* FIXME: use a property */
+ dlg->priv->translation_memory = translation_memory;
+
+ return GTK_WIDGET (dlg);
+}
diff --git a/src/translation-memory/gtr-translation-memory-dialog.h
b/src/translation-memory/gtr-translation-memory-dialog.h
new file mode 100644
index 00000000..7a6ed2d2
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-dialog.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * 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/>.
+ */
+
+#ifndef __GTR_TRANSLATION_MEMORY_DIALOG_H__
+#define __GTR_TRANSLATION_MEMORY_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include "gtr-translation-memory.h"
+
+G_BEGIN_DECLS
+
+#define GTR_TYPE_TRANSLATION_MEMORY_DIALOG (gtr_translation_memory_dialog_get_type ())
+#define GTR_TRANSLATION_MEMORY_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GTR_TYPE_TRANSLATION_MEMORY_DIALOG, GtrTranslationMemoryDialog))
+#define GTR_TRANSLATION_MEMORY_DIALOG_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GTR_TYPE_TRANSLATION_MEMORY_DIALOG, GtrTranslationMemoryDialog const))
+#define GTR_TRANSLATION_MEMORY_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
GTR_TYPE_TRANSLATION_MEMORY_DIALOG, GtrTranslationMemoryDialogClass))
+#define GTR_IS_TRANSLATION_MEMORY_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
GTR_TYPE_TRANSLATION_MEMORY_DIALOG))
+#define GTR_IS_TRANSLATION_MEMORY_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
GTR_TYPE_TRANSLATION_MEMORY_DIALOG))
+#define GTR_TRANSLATION_MEMORY_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GTR_TYPE_TRANSLATION_MEMORY_DIALOG, GtrTranslationMemoryDialogClass))
+
+typedef struct _GtrTranslationMemoryDialog GtrTranslationMemoryDialog;
+typedef struct _GtrTranslationMemoryDialogClass GtrTranslationMemoryDialogClass;
+typedef struct _GtrTranslationMemoryDialogPrivate GtrTranslationMemoryDialogPrivate;
+
+struct _GtrTranslationMemoryDialog
+{
+ GtkDialog parent;
+
+ GtrTranslationMemoryDialogPrivate *priv;
+};
+
+struct _GtrTranslationMemoryDialogClass
+{
+ GtkDialogClass parent_class;
+};
+
+GType gtr_translation_memory_dialog_get_type (void) G_GNUC_CONST;
+
+GtkWidget *gtr_translation_memory_dialog_new (GtrTranslationMemory *translation_memory);
+
+G_END_DECLS
+
+#endif /* __GTR_TRANSLATION_MEMORY_DIALOG_H__ */
diff --git a/src/translation-memory/gtr-translation-memory-dialog.ui
b/src/translation-memory/gtr-translation-memory-dialog.ui
new file mode 100644
index 00000000..f77e5292
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-dialog.ui
@@ -0,0 +1,322 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkDialog" id="translation-memory-dialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <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">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button1">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="translation-memory-box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkBox" id="vbox9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label20">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Database:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkBox" id="hbox8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkLabel" id="label25">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="vbox11">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label26">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Select the directory which
contains PO files:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="hbox9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="directory-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="xalign">0.0099999997764825821</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="search-button">
+ <property name="label">gtk-find</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="add-database-button">
+ <property name="label" translatable="yes">Add to Database</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="add-database-progressbar">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="vbox10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label21">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Configuration:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkBox" id="hbox7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkCheckButton" id="use-lang-profile-in-tm">
+ <property name="label" translatable="yes">Use only files with this
name:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="tm-lang-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="0">button1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/src/translation-memory/gtr-translation-memory-ui.c
b/src/translation-memory/gtr-translation-memory-ui.c
new file mode 100644
index 00000000..db107175
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-ui.c
@@ -0,0 +1,495 @@
+/*
+ * 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/>.
+ *
+ * Authors:
+ * Pablo Sanxiao <psanxiao gmail com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gtr-application.h"
+#include "gtr-po.h"
+#include "gtr-translation-memory.h"
+#include "gtr-translation-memory-ui.h"
+#include "gtr-tab.h"
+#include "gtr-utils.h"
+#include "gtr-window.h"
+#include "gtr-debug.h"
+
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#define MAX_ELEMENTS 9
+
+#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
+{
+ GtrTranslationMemory *translation_memory;
+ GtkWidget *tree_view;
+ GtrTab *tab;
+
+ gchar **tm_list;
+ gint *tm_list_id;
+
+ 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;
+
+ view = gtr_tab_get_active_view (tm_ui->priv->tab);
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ 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, translation);
+
+ gtk_text_buffer_begin_user_action (buffer);
+ 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]);
+}
+
+static void
+free_match (gpointer data)
+{
+ GtrTranslationMemoryMatch *match = (GtrTranslationMemoryMatch *) data;
+
+ g_free (match->match);
+ g_slice_free (GtrTranslationMemoryMatch, match);
+}
+
+static void
+showed_message_cb (GtrTab *tab, GtrMsg *msg, GtrTranslationMemoryUi *tm_ui)
+{
+ GtkListStore *model;
+ GtkTreeIter iter;
+ GtkTreeViewColumn *level_column;
+ const gchar *msgid;
+ gint i;
+ gint j;
+ GList *tm_list = NULL;
+ GList *l = NULL;
+ GList *renderers_list = NULL;
+ GtkWidget *tm_item;
+ GtkWidget *tm_menu;
+ GtkWidget *items_menu;
+ GtkWidget *window;
+ gchar *item_name;
+
+ model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tm_ui->priv->tree_view)));
+
+ window = gtk_widget_get_toplevel (GTK_WIDGET (tm_ui));
+
+ g_signal_connect (tm_ui->priv->tree_view,
+ "size_allocate",
+ G_CALLBACK (tree_view_size_cb), tm_ui->priv->tree_view);
+
+ if (tm_ui->priv->msg)
+ g_object_unref (tm_ui->priv->msg);
+ tm_ui->priv->msg = g_object_ref (msg);
+
+ msgid = gtr_msg_get_msgid (msg);
+
+ tm_list = gtr_translation_memory_lookup (tm_ui->priv->translation_memory, msgid);
+ g_strfreev (tm_ui->priv->tm_list);
+
+ gtk_list_store_clear (model);
+ tm_ui->priv->tm_list = g_new (gchar *, MAX_ELEMENTS + 1);
+ tm_ui->priv->tm_list_id = g_new (gint, MAX_ELEMENTS + 1);
+
+ i = 0;
+ for (l = tm_list; l && i < MAX_ELEMENTS; l = l->next)
+ {
+ GtrTranslationMemoryMatch *match = (GtrTranslationMemoryMatch *) l->data;
+
+ tm_ui->priv->tm_list_id[i] = match->id;
+ tm_ui->priv->tm_list[i] = g_strdup (match->match);
+ level_column = gtk_tree_view_get_column (GTK_TREE_VIEW (tm_ui->priv->tree_view), 0);
+ renderers_list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (level_column));
+
+ g_object_set (renderers_list->data,
+ "accel-mods", GDK_CONTROL_MASK, NULL);
+ g_list_free (renderers_list);
+
+ gtk_list_store_append (model, &iter);
+ gtk_list_store_set (model, &iter,
+ SHORTCUT_COLUMN, GDK_KEY_1 + i,
+ STRING_COLUMN, match->match,
+ LEVEL_COLUMN, match->level,
+ -1);
+ i++;
+ }
+
+ /* Ensure last element is NULL */
+ tm_ui->priv->tm_list[i] = NULL;
+
+ g_list_free_full (tm_list, free_match);
+}
+
+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 (!selection || !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;
+ gint i;
+ gchar *translation;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tm_ui->priv->tree_view));
+ if (!selection || !gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter,
+ STRING_COLUMN, &translation,
+ -1);
+
+ for (i = 0; tm_ui->priv->tm_list[i]; i++)
+ if (!strcmp (tm_ui->priv->tm_list[i], translation))
+ break;
+
+ gtr_translation_memory_remove (tm_ui->priv->translation_memory, tm_ui->priv->tm_list_id[i]);
+
+ 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;
+ GtkWidget *menu;
+ GtkWidget *item;
+ GtkWidget *image;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->tree_view));
+
+ 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, TRUE);
+
+ 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)
+{
+ GtkTreeView *treeview;
+ GtkTreeViewColumn *column;
+ GList *renderers_list = NULL;
+ gint size;
+
+ treeview = GTK_TREE_VIEW (user_data);
+
+ column = gtk_tree_view_get_column (treeview, 2);
+ renderers_list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
+
+ size = gtk_tree_view_column_get_width (column);
+
+ g_object_set (renderers_list->data, "wrap-width", MAX(1, size - 10), NULL);
+
+ 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_init (GtrTranslationMemoryUi * tm_ui)
+{
+ GtrTranslationMemoryUiPrivate *priv;
+ GtkListStore *model;
+ GtkCellRenderer *level_renderer, *string_renderer, *shortcut_renderer;
+ GtkTreeViewColumn *shortcut, *string, *level;
+
+ tm_ui->priv = GTR_TRANSLATION_MEMORY_UI_GET_PRIVATE (tm_ui);
+ priv = tm_ui->priv;
+ tm_ui->priv->tm_list = NULL;
+ tm_ui->priv->popup_menu = NULL;
+ tm_ui->priv->msg = NULL;
+
+ priv->tree_view = gtk_tree_view_new ();
+ gtk_widget_show (priv->tree_view);
+
+ model = gtk_list_store_new (N_COLUMNS, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view),
+ GTK_TREE_MODEL (model));
+
+ shortcut_renderer = gtk_cell_renderer_accel_new ();
+ shortcut = gtk_tree_view_column_new_with_attributes (_("Shortcut"),
+ shortcut_renderer,
+ "accel-key",
+ SHORTCUT_COLUMN, NULL);
+ g_object_set (shortcut_renderer, "width", 80, NULL);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), shortcut);
+
+ level_renderer = gtk_cell_renderer_progress_new ();
+ level = gtk_tree_view_column_new_with_attributes (_("Level"),
+ level_renderer,
+ "value", LEVEL_COLUMN,
+ NULL);
+ g_object_set (level_renderer, "width", 80, NULL);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), level);
+
+ string_renderer = gtk_cell_renderer_text_new ();
+ string = gtk_tree_view_column_new_with_attributes (_("String"),
+ string_renderer,
+ "text", STRING_COLUMN,
+ NULL);
+ gtk_tree_view_column_set_sizing (string, GTK_TREE_VIEW_COLUMN_FIXED);
+
+ g_object_set (string_renderer,
+ "ypad", 0,
+ "xpad", 5,
+ "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
+gtr_translation_memory_ui_dispose (GObject * object)
+{
+ GtrTranslationMemoryUi *tm_ui = GTR_TRANSLATION_MEMORY_UI (object);
+
+ DEBUG_PRINT ("Dispose translation memory ui");
+
+ g_clear_object (&tm_ui->priv->msg);
+
+ 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);
+
+ DEBUG_PRINT ("Finalize translation memory ui");
+
+ g_strfreev (tm_ui->priv->tm_list);
+
+ G_OBJECT_CLASS (gtr_translation_memory_ui_parent_class)->finalize (object);
+}
+
+static void
+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;
+}
+
+GtkWidget *
+gtr_translation_memory_ui_new (GtkWidget *tab,
+ GtrTranslationMemory *translation_memory)
+{
+ GtrTranslationMemoryUi *tm_ui;
+ tm_ui = g_object_new (GTR_TYPE_TRANSLATION_MEMORY_UI, NULL);
+
+ tm_ui->priv->tab = GTR_TAB (tab);
+ tm_ui->priv->translation_memory = translation_memory;
+
+ g_signal_connect (tab,
+ "showed-message", G_CALLBACK (showed_message_cb), tm_ui);
+
+ /* Scrolledwindow needs to be realized to add a widget */
+ gtk_container_add (GTK_CONTAINER (tm_ui), tm_ui->priv->tree_view);
+
+ return GTK_WIDGET (tm_ui);
+}
diff --git a/src/translation-memory/gtr-translation-memory-ui.h
b/src/translation-memory/gtr-translation-memory-ui.h
new file mode 100644
index 00000000..536cfc9f
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-ui.h
@@ -0,0 +1,62 @@
+/*
+ * 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/>.
+ *
+ * Authors:
+ * Pablo Sanxiao <psanxiao gmail com>
+ */
+
+#ifndef __TRANSLATION_MEMORY_UI_H__
+#define __TRANSLATION_MEMORY_UI_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTR_TYPE_TRANSLATION_MEMORY_UI (gtr_translation_memory_ui_get_type ())
+#define GTR_TRANSLATION_MEMORY_UI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),
GTR_TYPE_TRANSLATION_MEMORY_UI, GtrTranslationMemoryUi))
+#define GTR_TRANSLATION_MEMORY_UI_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k),
GTR_TYPE_TRANSLATION_MEMORY_UI, GtrTranslationMemoryUiClass))
+#define GTR_IS_TRANSLATION_MEMORY_UI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
GTR_TYPE_TRANSLATION_MEMORY_UI))
+#define GTR_IS_TRANSLATION_MEMORY_UI_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k),
GTR_TYPE_TRANSLATION_MEMORY_UI))
+#define GTR_TRANSLATION_MEMORY_UI_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
GTR_TYPE_TRANSLATION_MEMORY_UI, GtrTranslationMemoryUiClass))
+
+typedef struct _GtrTranslationMemoryUi GtrTranslationMemoryUi;
+typedef struct _GtrTranslationMemoryUiClass GtrTranslationMemoryUiClass;
+typedef struct _GtrTranslationMemoryUiPrivate GtrTranslationMemoryUiPrivate;
+
+struct _GtrTranslationMemoryUi
+{
+ GtkScrolledWindow parent_instance;
+
+ /*< private > */
+ GtrTranslationMemoryUiPrivate *priv;
+};
+
+struct _GtrTranslationMemoryUiClass
+{
+ GtkScrolledWindowClass parent_class;
+};
+
+GType gtr_translation_memory_ui_get_type (void) G_GNUC_CONST;
+
+GType gtr_translation_memory_ui_register_type (GTypeModule *module);
+
+GtkWidget *gtr_translation_memory_ui_new (GtkWidget *tab,
+ GtrTranslationMemory *translation_memory);
+
+G_END_DECLS
+#endif /* __TRANSLATION_MEMORY_UI_H__ */
diff --git a/src/translation-memory/gtr-translation-memory-utils.c
b/src/translation-memory/gtr-translation-memory-utils.c
new file mode 100644
index 00000000..9c5580ad
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-utils.c
@@ -0,0 +1,96 @@
+/*
+ * (C) 2001 Fatih Demir <kabalak kabalak net>
+ * 2012 Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * gtranslator 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gtranslator 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/>.
+ *
+ * Authors:
+ * Ignacio Casal Quinteiro <icq gnome org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gtr-translation-memory-utils.h"
+
+#include <string.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+
+/**
+ * gtr_scan_dir:
+ * @dir: the dir to parse
+ * @list: the list where to store the GFiles
+ * @po_name: the name of the specific po file to search or NULL.
+ *
+ * Scans the directory and subdirectories of @dir looking for filenames remained
+ * with .po or files that matches @po_name. @list must be freed with
+ * g_slist_free_full (list, g_object_unref).
+ */
+void
+gtr_scan_dir (GFile * dir, GSList ** list, const gchar * po_name)
+{
+ GFileInfo *info;
+ GError *error;
+ GFile *file;
+ GFileEnumerator *enumerator;
+
+ error = NULL;
+ enumerator = g_file_enumerate_children (dir,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, &error);
+ if (enumerator)
+ {
+ error = NULL;
+
+ while ((info =
+ g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL)
+ {
+ const gchar *name;
+ gchar *filename;
+
+ name = g_file_info_get_name (info);
+ file = g_file_get_child (dir, name);
+
+ if (po_name != NULL)
+ {
+ if (g_str_has_suffix (po_name, ".po"))
+ filename = g_strdup (po_name);
+ else
+ filename = g_strconcat (po_name, ".po", NULL);
+ }
+ else
+ filename = g_strdup (".po");
+
+ if (g_str_has_suffix (name, filename))
+ *list = g_slist_prepend (*list, file);
+ g_free (filename);
+
+ gtr_scan_dir (file, list, po_name);
+ g_object_unref (info);
+ }
+ g_file_enumerator_close (enumerator, NULL, NULL);
+ g_object_unref (enumerator);
+
+ if (error)
+ {
+ g_warning ("%s", error->message);
+ }
+ }
+}
+
diff --git a/src/translation-memory/gtr-translation-memory-utils.h
b/src/translation-memory/gtr-translation-memory-utils.h
new file mode 100644
index 00000000..07660a54
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-utils.h
@@ -0,0 +1,33 @@
+/*
+ * (C) 2001 Fatih Demir <kabalak kabalak net>
+ * 2012 Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * gtranslator 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gtranslator 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/>.
+ *
+ * Authors:
+ * Fatih Demir <kabalak kabalak net>
+ * Ignacio Casal Quinteiro <icq gnome org>
+ */
+
+#ifndef GTR_TRANSLATION_MEMORY_UTILS_H
+#define GTR_TRANSLATION_MEMORY_UTILS_H
+
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+void gtr_scan_dir (GFile *dir,
+ GSList **list,
+ const gchar *po_name);
+
+#endif
diff --git a/src/translation-memory/gtr-translation-memory.c b/src/translation-memory/gtr-translation-memory.c
new file mode 100644
index 00000000..95b7c6fc
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory.c
@@ -0,0 +1,208 @@
+/*
+ * 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/>.
+ */
+
+#include "gtr-translation-memory.h"
+
+G_DEFINE_INTERFACE (GtrTranslationMemory, gtr_translation_memory, G_TYPE_OBJECT)
+
+/**
+ * gtr_translation_memory_store:
+ * @obj: a #GtrTranslationMemory
+ * @msg: message
+ *
+ * Stores the @msg in the database.
+ */
+gboolean
+gtr_translation_memory_store (GtrTranslationMemory * obj, GtrMsg * msg)
+{
+ g_return_val_if_fail (GTR_IS_TRANSLATION_MEMORY (obj), FALSE);
+ return GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->store (obj, msg);
+}
+
+/* Default implementation */
+static gboolean
+gtr_translation_memory_store_default (GtrTranslationMemory * obj, GtrMsg * msg)
+{
+ g_return_val_if_reached (FALSE);
+}
+
+/**
+ * gtr_translation_memory_store_list:
+ * @obj: a #GtrTranslationMemory
+ * @msgs: list of messages (#GtrMsg)
+ *
+ * Stores the messages from @msgs in the database.
+ */
+gboolean
+gtr_translation_memory_store_list (GtrTranslationMemory * obj, GList * msgs)
+{
+ g_return_val_if_fail (GTR_IS_TRANSLATION_MEMORY (obj), FALSE);
+ return GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->store_list (obj, msgs);
+}
+
+/* Default implementation */
+static gboolean
+gtr_translation_memory_store_list_default (GtrTranslationMemory * obj,
+ GList * msgs)
+{
+ GList * l;
+
+ for (l = msgs; l; l = g_list_next (l))
+ {
+ GtrMsg *msg = GTR_MSG (l->data);
+ gboolean result;
+
+ if (!gtr_msg_is_translated (msg))
+ continue;
+
+ result = gtr_translation_memory_store (obj, msg);
+ if (!result)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * 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,
+ gint translation_id)
+{
+ g_return_if_fail (GTR_IS_TRANSLATION_MEMORY (obj));
+ return GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->remove (obj,
+ translation_id);
+}
+
+/* Default implementation */
+static void
+gtr_translation_memory_remove_default (GtrTranslationMemory * obj,
+ gint translation_id)
+{
+}
+
+/**
+ * gtr_translation_memory_lookup:
+ * @obj: a #GtrTranslationMemory
+ * @phrase: the unstranslated text to search for translations.
+ *
+ * Looks for the @phrase in the database and gets a list of the #GtrTranslationMemoryMatch.
+ *
+ * Returns: a list of #GtrTranslationMemoryMatch.
+ */
+GList *
+gtr_translation_memory_lookup (GtrTranslationMemory * obj,
+ const gchar * phrase)
+{
+ g_return_val_if_fail (GTR_IS_TRANSLATION_MEMORY (obj), 0);
+ return GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->lookup (obj, phrase);
+}
+
+/* Default implementation */
+static GList *
+gtr_translation_memory_lookup_default (GtrTranslationMemory *obj,
+ const gchar * phrase)
+{
+ g_return_val_if_reached (0);
+}
+
+/**
+ * gtr_translation_memory_set_max_omits:
+ * @omits: the number of omits
+ *
+ * Sets the number of omits used in the search.
+ */
+void
+gtr_translation_memory_set_max_omits (GtrTranslationMemory * obj, gsize omits)
+{
+ g_return_if_fail (GTR_IS_TRANSLATION_MEMORY (obj));
+ GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->set_max_omits (obj, omits);
+}
+
+/* Default implementation */
+static void
+gtr_translation_memory_set_max_omits_default (GtrTranslationMemory * obj,
+ gsize omits)
+{
+ g_return_if_reached ();
+}
+
+/**
+ * gtr_translation_memory_set_max_delta:
+ * @delta: the difference in the length of strings
+ *
+ * Sets the difference in the length of string for searching in the database.
+ */
+void
+gtr_translation_memory_set_max_delta (GtrTranslationMemory * obj, gsize delta)
+{
+ g_return_if_fail (GTR_IS_TRANSLATION_MEMORY (obj));
+ GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->set_max_delta (obj, delta);
+}
+
+/* Default implementation */
+static void
+ gtr_translation_memory_set_max_delta_default
+ (GtrTranslationMemory * obj, gsize omits)
+{
+ g_return_if_reached ();
+}
+
+/**
+ * gtr_translation_memory_set_max_items:
+ * @items: the max item to return in lookup
+ *
+ * Sets the number of item to return in gtr_translation_memory_lookup().
+ */
+void
+gtr_translation_memory_set_max_items (GtrTranslationMemory * obj, gint items)
+{
+ g_return_if_fail (GTR_IS_TRANSLATION_MEMORY (obj));
+ GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->set_max_items (obj, items);
+}
+
+/* Default implementation */
+static void
+gtr_translation_memory_set_max_items_default (GtrTranslationMemory * obj, gint items)
+{
+ g_return_if_reached ();
+}
+
+static void
+gtr_translation_memory_default_init (GtrTranslationMemoryInterface *iface)
+{
+ static gboolean initialized = FALSE;
+
+ iface->store = gtr_translation_memory_store_default;
+ iface->store_list = gtr_translation_memory_store_list_default;
+ iface->remove = gtr_translation_memory_remove_default;
+ iface->lookup = gtr_translation_memory_lookup_default;
+ iface->set_max_omits = gtr_translation_memory_set_max_omits_default;
+ iface->set_max_delta = gtr_translation_memory_set_max_delta_default;
+ iface->set_max_items = gtr_translation_memory_set_max_items_default;
+
+ if (!initialized)
+ initialized = TRUE;
+}
+
+
diff --git a/src/translation-memory/gtr-translation-memory.gresource.xml
b/src/translation-memory/gtr-translation-memory.gresource.xml
new file mode 100644
index 00000000..17f797cd
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/gtranslator/plugins/translation-memory/ui">
+ <file preprocess="xml-stripblanks">gtr-translation-memory-dialog.ui</file>
+ </gresource>
+</gresources>
diff --git a/src/translation-memory/gtr-translation-memory.h b/src/translation-memory/gtr-translation-memory.h
new file mode 100644
index 00000000..a3f29abf
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory.h
@@ -0,0 +1,80 @@
+/*
+ * 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/>.
+ */
+
+#ifndef _GTR_TRANSLATION_MEMORY_H_
+#define _GTR_TRANSLATION_MEMORY_H_
+
+#include <glib-object.h>
+#include "gtr-msg.h"
+
+G_BEGIN_DECLS
+#define GTR_TYPE_TRANSLATION_MEMORY (gtr_translation_memory_get_type ())
+#define GTR_TRANSLATION_MEMORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTR_TYPE_TRANSLATION_MEMORY,
GtrTranslationMemory))
+#define GTR_IS_TRANSLATION_MEMORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTR_TYPE_TRANSLATION_MEMORY))
+#define GTR_TRANSLATION_MEMORY_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj),
GTR_TYPE_TRANSLATION_MEMORY, GtrTranslationMemoryInterface))
+
+typedef struct _GtrTranslationMemory GtrTranslationMemory;
+typedef struct _GtrTranslationMemoryInterface GtrTranslationMemoryInterface;
+
+struct _GtrTranslationMemoryInterface
+{
+ GTypeInterface g_iface;
+
+ gboolean (*store) (GtrTranslationMemory * obj, GtrMsg * msg);
+ gboolean (*store_list) (GtrTranslationMemory * obj, GList * msgs);
+ void (*remove) (GtrTranslationMemory *obj,
+ gint translation_id);
+
+ GList *(*lookup) (GtrTranslationMemory * obj, const gchar * phrase);
+ void (*set_max_omits) (GtrTranslationMemory * obj, gsize omits);
+ void (*set_max_delta) (GtrTranslationMemory * obj, gsize delta);
+ void (*set_max_items) (GtrTranslationMemory * obj, gint items);
+};
+
+typedef struct _GtrTranslationMemoryMatch GtrTranslationMemoryMatch;
+struct _GtrTranslationMemoryMatch
+{
+ gchar *match;
+ gint level;
+ gint id;
+};
+
+GType gtr_translation_memory_get_type (void);
+
+gboolean 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,
+ gint translation_id);
+
+GList *gtr_translation_memory_lookup (GtrTranslationMemory *obj,
+ const gchar *phrase);
+
+void gtr_translation_memory_set_max_omits (GtrTranslationMemory *obj,
+ gsize omits);
+
+void gtr_translation_memory_set_max_delta (GtrTranslationMemory *obj,
+ gsize delta);
+
+void gtr_translation_memory_set_max_items (GtrTranslationMemory *obj,
+ gint items);
+
+G_END_DECLS
+#endif
diff --git a/src/translation-memory/meson.build b/src/translation-memory/meson.build
new file mode 100644
index 00000000..2ed682da
--- /dev/null
+++ b/src/translation-memory/meson.build
@@ -0,0 +1,36 @@
+memory_resource_data = files(
+ 'gtr-translation-memory-dialog.ui',
+)
+
+memory_resource = files('gtr-translation-memory.gresource.xml')
+
+sources += gnome.compile_resources(
+ 'gtr-translation-memory-resources', memory_resource,
+ source_dir: src_dir,
+ dependencies: memory_resource_data,
+ export: true
+)
+
+sources += files(
+ 'gtr-translation-memory.c',
+ 'gtr-translation-memory-dialog.c',
+ 'gtr-translation-memory-ui.c',
+ 'gtr-translation-memory-utils.c',
+)
+
+subdir('gda')
+
+# GSettings schema
+memory_schema_conf = configuration_data()
+memory_schema_conf.set('GETTEXT_PACKAGE', meson.project_name())
+
+memory_schema = 'org.gnome.gtranslator.plugins.translation-memory.gschema.xml'
+
+schema_xml = configure_file(
+ input: memory_schema + '.in',
+ output: memory_schema,
+ install: true,
+ install_dir: gtranslator_schemadir,
+ configuration: memory_schema_conf
+)
+
diff --git a/src/translation-memory/org.gnome.gtranslator.plugins.translation-memory.gschema.xml.in
b/src/translation-memory/org.gnome.gtranslator.plugins.translation-memory.gschema.xml.in
new file mode 100644
index 00000000..8bfdae84
--- /dev/null
+++ b/src/translation-memory/org.gnome.gtranslator.plugins.translation-memory.gschema.xml.in
@@ -0,0 +1,43 @@
+<schemalist>
+ <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.gtranslator.plugins.translation-memory"
path="/org/gnome/gtranslator/plugins/translation-memory/">
+ <key name="po-directory" type="s">
+ <default>''</default>
+ <summary>PO directory</summary>
+ <description>
+ Directory containing PO files to add to the translation memory.
+ </description>
+ </key>
+ <key name="restrict-to-filename" type="b">
+ <default>false</default>
+ <summary>Restrict search by filename</summary>
+ <description>
+ If true, only include files with a specified filename when searching
+ the translation memory.
+ </description>
+ </key>
+ <key name="filename-restriction" type="s">
+ <default>''</default>
+ <summary>Filename to restrict search to</summary>
+ <description>
+ Filename to which searching of the translation memory should be
+ restricted.
+ </description>
+ </key>
+ <key name="max-missing-words" type="i">
+ <default>2</default>
+ <summary>Maximum number of missing words</summary>
+ <description>
+ Maximum number of words that can be missing from a message displayed as
+ a match by the translation memory.
+ </description>
+ </key>
+ <key name="max-length-diff" type="i">
+ <default>2</default>
+ <summary>Maximum difference in message length</summary>
+ <description>
+ Maximum difference in length between messages displayed as matches by
+ the translation memory.
+ </description>
+ </key>
+ </schema>
+</schemalist>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]