/* * Copyright (C) 2004, 2005 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include "translate-service-private.h" #include "translate-pair-private.h" #include "translate.h" #define LOCK(service) g_mutex_lock((service)->priv->mutex) #define UNLOCK(service) g_mutex_unlock((service)->priv->mutex) enum { PROP_0, PROP_NAME, PROP_NICK, PROP_MAX_CHUNK_LEN, PROP_PAIRS }; struct _TranslateServicePrivate { char *name; char *nick; unsigned int max_chunk_len; GMutex *mutex; gboolean pairs_set; GSList *pairs; }; static GObjectClass *parent_class = NULL; static void translate_service_register_type (GType *type); static void translate_service_class_init (TranslateServiceClass *class); static void translate_service_init (TranslateService *service); static void translate_service_finalize (GObject *object); static void translate_service_set_property (GObject *object, unsigned int prop_id, const GValue *value, GParamSpec *pspec); static void translate_service_get_property (GObject *object, unsigned int prop_id, GValue *value, GParamSpec *pspec); GType translate_service_get_type (void) { static GType type; static GOnce once = G_ONCE_INIT; g_once(&once, (GThreadFunc) translate_service_register_type, &type); return type; } static void translate_service_register_type (GType *type) { static const GTypeInfo info = { sizeof(TranslateServiceClass), NULL, NULL, (GClassInitFunc) translate_service_class_init, NULL, NULL, sizeof(TranslateService), 0, (GInstanceInitFunc) translate_service_init }; *type = g_type_register_static(G_TYPE_OBJECT, "TranslateService", &info, G_TYPE_FLAG_ABSTRACT); } static void translate_service_class_init (TranslateServiceClass *class) { GObjectClass *object_class = G_OBJECT_CLASS(class); g_type_class_add_private(class, sizeof(TranslateServicePrivate)); parent_class = g_type_class_peek_parent(class); object_class->finalize = translate_service_finalize; object_class->set_property = translate_service_set_property; object_class->get_property = translate_service_get_property; g_object_class_install_property(object_class, PROP_NAME, g_param_spec_string("name", _("Name"), _("The service symbolic name, encoded in ASCII"), NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property(object_class, PROP_NICK, g_param_spec_string("nick", _("Nick"), _("The service human-readable name"), NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property(object_class, PROP_MAX_CHUNK_LEN, g_param_spec_uint("max-chunk-len", _("Maximum chunk length"), _("The maximum length of an input chunk, in characters (0 means unlimited)"), 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property(object_class, PROP_PAIRS, g_param_spec_pointer("pairs", _("Pairs"), _("The list of language pairs this service implements"), G_PARAM_READABLE)); } static void translate_service_init (TranslateService *service) { service->priv = G_TYPE_INSTANCE_GET_PRIVATE(service, TRANSLATE_TYPE_SERVICE, TranslateServicePrivate); service->priv->mutex = g_mutex_new(); } static void translate_service_finalize (GObject *object) { TranslateService *service = TRANSLATE_SERVICE(object); g_free(service->priv->name); g_free(service->priv->nick); g_mutex_free(service->priv->mutex); g_slist_foreach(service->priv->pairs, (GFunc) g_object_unref, NULL); g_slist_free(service->priv->pairs); parent_class->finalize(object); } static void translate_service_set_property (GObject *object, unsigned int prop_id, const GValue *value, GParamSpec *pspec) { TranslateService *service = TRANSLATE_SERVICE(object); switch (prop_id) { case PROP_NAME: service->priv->name = g_value_dup_string(value); break; case PROP_NICK: service->priv->nick = g_value_dup_string(value); break; case PROP_MAX_CHUNK_LEN: service->priv->max_chunk_len = g_value_get_uint(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void translate_service_get_property (GObject *object, unsigned int prop_id, GValue *value, GParamSpec *pspec) { TranslateService *service = TRANSLATE_SERVICE(object); switch (prop_id) { case PROP_NAME: g_value_set_string(value, service->priv->name); break; case PROP_NICK: g_value_set_string(value, service->priv->nick); break; case PROP_MAX_CHUNK_LEN: g_value_set_uint(value, service->priv->max_chunk_len); break; case PROP_PAIRS: LOCK(service); if (! service->priv->pairs_set) { TranslateServiceClass *class = TRANSLATE_SERVICE_GET_CLASS(service); GError *err = NULL; if (class->get_pairs) { if (class->get_pairs(service, &service->priv->pairs, NULL, NULL, &err)) { GSList *l; /* hunt down programming errors */ for (l = service->priv->pairs; l != NULL; l = l->next) { TranslatePair *pair = l->data; TranslatePairFlags flags = translate_pair_get_flags(pair); if (! class->translate_text && (flags & TRANSLATE_PAIR_TEXT)) { g_critical(_("%s: the TRANSLATE_PAIR_TEXT flag is set for %s->%s, but the translate_text method is not implemented (this indicates a programming error in the service implementation): unsetting the flag"), service->priv->nick, translate_pair_get_from(pair), translate_pair_get_to(pair)); flags &= ~TRANSLATE_PAIR_TEXT; } if (! class->translate_web_page && (flags & TRANSLATE_PAIR_WEB_PAGE)) { g_critical(_("%s: the TRANSLATE_PAIR_WEB_PAGE flag is set for %s->%s, but the translate_web_page method is not implemented (this indicates a programming error in the service implementation): unsetting the flag"), service->priv->nick, translate_pair_get_from(pair), translate_pair_get_to(pair)); flags &= ~TRANSLATE_PAIR_WEB_PAGE; } translate_pair_set_flags(pair, flags); } } else { g_warning(_("%s: unable to get language pairs: %s"), service->priv->nick, err->message); g_error_free(err); } } else g_critical(_("%s: the get_pairs method is not implemented (this indicates a programming error in the service implementation)"), service->priv->nick); service->priv->pairs_set = TRUE; } UNLOCK(service); g_value_set_pointer(value, service->priv->pairs); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } /** * translate_service_get_name: * @service: a service. * * Gets the symbolic name of @service. * * Return value: the symbolic name of @service, encoded in ASCII. **/ const char * translate_service_get_name (TranslateService *service) { g_return_val_if_fail(TRANSLATE_IS_SERVICE(service), NULL); return service->priv->name; } /** * translate_service_get_nick: * @service: a service. * * Gets the human-readable name of @service. * * Return value: the human-readable name of @service. **/ const char * translate_service_get_nick (TranslateService *service) { g_return_val_if_fail(TRANSLATE_IS_SERVICE(service), NULL); return service->priv->nick; } /** * translate_service_get_max_chunk_len: * @service: a service. * * Gets the maximum chunk length of @service. * * Return value: the maximum chunk length of @service, in characters. **/ unsigned int translate_service_get_max_chunk_len (TranslateService *service) { g_return_val_if_fail(TRANSLATE_IS_SERVICE(service), 0); return service->priv->max_chunk_len; } /** * translate_service_get_pairs: * @service: a service. * * Gets the list of language pairs implemented by @service. * * Return value: a list of #TranslatePair objects. **/ const GSList * translate_service_get_pairs (TranslateService *service) { const GSList *pairs; g_return_val_if_fail(TRANSLATE_IS_SERVICE(service), NULL); g_object_get(G_OBJECT(service), "pairs", &pairs, NULL); return pairs; } char * translate_service_translate_text (TranslateService *service, const char *text, const char *from, const char *to, TranslateProgressFunc progress_func, gpointer user_data, GError **err) { g_return_val_if_fail(TRANSLATE_IS_SERVICE(service), NULL); g_return_val_if_fail(TRANSLATE_SERVICE_GET_CLASS(service)->translate_text != NULL, NULL); g_return_val_if_fail(text != NULL, NULL); g_return_val_if_fail(from != NULL, NULL); g_return_val_if_fail(to != NULL, NULL); return TRANSLATE_SERVICE_GET_CLASS(service)->translate_text(service, text, from, to, progress_func, user_data, err); } char * translate_service_translate_web_page (TranslateService *service, const char *url, const char *from, const char *to, TranslateProgressFunc progress_func, gpointer user_data, GError **err) { g_return_val_if_fail(TRANSLATE_IS_SERVICE(service), NULL); g_return_val_if_fail(TRANSLATE_SERVICE_GET_CLASS(service)->translate_web_page != NULL, NULL); g_return_val_if_fail(url != NULL, NULL); g_return_val_if_fail(from != NULL, NULL); g_return_val_if_fail(to != NULL, NULL); return TRANSLATE_SERVICE_GET_CLASS(service)->translate_web_page(service, url, from, to, progress_func, user_data, err); }