Commit 70bc039b authored by Shaun McCance's avatar Shaun McCance

libyelp: All the hooks in place for search stuff

parent 08d48319
......@@ -34,6 +34,7 @@ PKG_CHECK_MODULES(YELP,
libxml-2.0 >= 2.6.5
libxslt >= 1.1.4
libexslt >= 0.8.1
sqlite3
webkitgtk-3.0 >= 1.3.2
yelp-xsl >= 2.91.9
])
......
lib_LTLIBRARIES = libyelp.la
libyelp_la_SOURCES = \
libyelp_la_SOURCES = \
yelp-bookmarks.c \
yelp-debug.c \
yelp-error.c \
......@@ -17,12 +17,14 @@ libyelp_la_SOURCES = \
yelp-marshal.c \
yelp-settings.c \
yelp-simple-document.c \
yelp-sqlite-storage.c \
yelp-storage.c \
yelp-transform.c \
yelp-uri.c \
yelp-types.c \
yelp-view.c
EXTRA_DIST = \
EXTRA_DIST = \
yelp-bz2-decompressor.h \
yelp-debug.h \
yelp-error.h \
......@@ -44,14 +46,14 @@ else
EXTRA_DIST += yelp-bz2-decompressor.c
endif
libyelp_la_CFLAGS = \
libyelp_la_CFLAGS = \
$(YELP_CFLAGS) \
-DDATADIR=\""$(datadir)"\" \
-DYELP_ICON_PATH=\"$(YELP_ICON_PATH)\"
libyelp_la_LIBADD = $(YELP_LIBS)
libyelp_headers = \
libyelp_headers = \
yelp-bookmarks.h \
yelp-docbook-document.h \
yelp-document.h \
......@@ -62,6 +64,8 @@ libyelp_headers = \
yelp-man-document.h \
yelp-settings.h \
yelp-simple-document.h \
yelp-sqlite-storage.h \
yelp-storage.h \
yelp-transform.h \
yelp-uri.h \
yelp-view.h
......@@ -70,7 +74,7 @@ libyelp_includedir = $(includedir)/libyelp/
libyelp_include_HEADERS = $(libyelp_headers) yelp-types.h
BUILT_SOURCES = \
BUILT_SOURCES = \
stamp-yelp-marshal.h \
yelp-marshal.c \
yelp-marshal.h \
......
......@@ -204,10 +204,15 @@ yelp_docbook_document_new (YelpUri *uri)
{
YelpDocbookDocument *docbook;
YelpDocbookDocumentPrivate *priv;
gchar *doc_uri;
g_return_val_if_fail (uri != NULL, NULL);
docbook = (YelpDocbookDocument *) g_object_new (YELP_TYPE_DOCBOOK_DOCUMENT, NULL);
doc_uri = yelp_uri_get_document_uri (uri);
docbook = (YelpDocbookDocument *) g_object_new (YELP_TYPE_DOCBOOK_DOCUMENT,
"document-uri", doc_uri,
NULL);
g_free (doc_uri);
priv = GET_PRIV (docbook);
priv->uri = g_object_ref (uri);
......
......@@ -36,6 +36,13 @@
#include "yelp-mallard-document.h"
#include "yelp-man-document.h"
#include "yelp-simple-document.h"
#include "yelp-storage.h"
enum {
PROP_0,
PROP_URI,
PROP_INDEXED
};
typedef struct _Request Request;
struct _Request {
......@@ -63,6 +70,11 @@ struct _YelpDocumentPriv {
Hash *reqs_by_page_id; /* Indexed by page ID, contains GSList */
GSList *reqs_pending; /* List of requests that need a page */
GSList *reqs_search; /* Pending search requests, not in reqs_all */
gboolean indexed;
gchar *doc_uri;
/* Real page IDs map to themselves, so this list doubles
* as a list of all valid page IDs.
*/
......@@ -90,18 +102,27 @@ static void yelp_document_class_init (YelpDocumentClass *klass);
static void yelp_document_init (YelpDocument *document);
static void yelp_document_dispose (GObject *object);
static void yelp_document_finalize (GObject *object);
static void document_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void document_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static gboolean document_request_page (YelpDocument *document,
const gchar *page_id,
GCancellable *cancellable,
YelpDocumentCallback callback,
gpointer user_data);
static void document_indexed (YelpDocument *document);
static const gchar * document_read_contents (YelpDocument *document,
const gchar *page_id);
static void document_finish_read (YelpDocument *document,
const gchar *contents);
static gchar * document_get_mime_type (YelpDocument *document,
const gchar *mime_type);
static void document_index (YelpDocument *document);
static Hash * hash_new (GDestroyNotify destroy);
static void hash_free (Hash *hash);
......@@ -204,9 +225,6 @@ yelp_document_get_for_uri (YelpUri *uri)
case YELP_URI_DOCUMENT_TYPE_HELP_LIST:
document = yelp_help_list_new (uri);
break;
case YELP_URI_DOCUMENT_TYPE_SEARCH:
/* FIXME */
break;
case YELP_URI_DOCUMENT_TYPE_NOT_FOUND:
case YELP_URI_DOCUMENT_TYPE_EXTERNAL:
case YELP_URI_DOCUMENT_TYPE_ERROR:
......@@ -231,11 +249,32 @@ yelp_document_class_init (YelpDocumentClass *klass)
object_class->dispose = yelp_document_dispose;
object_class->finalize = yelp_document_finalize;
object_class->get_property = document_get_property;
object_class->set_property = document_set_property;
klass->request_page = document_request_page;
klass->read_contents = document_read_contents;
klass->finish_read = document_finish_read;
klass->get_mime_type = document_get_mime_type;
klass->index = document_index;
g_object_class_install_property (object_class,
PROP_INDEXED,
g_param_spec_boolean ("indexed",
N_("Indexed"),
N_("Whether the document content has been indexed"),
FALSE,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_URI,
g_param_spec_string ("document-uri",
N_("Document URI"),
N_("The URI which identifies the document"),
NULL,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_type_class_add_private (klass, sizeof (YelpDocumentPriv));
}
......@@ -252,6 +291,7 @@ yelp_document_init (YelpDocument *document)
priv->reqs_by_page_id = hash_new ((GDestroyNotify) g_slist_free);
priv->reqs_all = NULL;
priv->reqs_pending = NULL;
priv->reqs_search = NULL;
priv->core_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
priv->page_ids = hash_new (g_free );
......@@ -280,6 +320,14 @@ yelp_document_dispose (GObject *object)
document->priv->reqs_all = NULL;
}
if (document->priv->reqs_search) {
g_slist_foreach (document->priv->reqs_search,
(GFunc) request_try_free,
NULL);
g_slist_free (document->priv->reqs_search);
document->priv->reqs_search = NULL;
}
G_OBJECT_CLASS (yelp_document_parent_class)->dispose (object);
}
......@@ -311,6 +359,52 @@ yelp_document_finalize (GObject *object)
G_OBJECT_CLASS (yelp_document_parent_class)->finalize (object);
}
static void
document_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
YelpDocument *document = YELP_DOCUMENT (object);
switch (prop_id) {
case PROP_INDEXED:
g_value_set_boolean (value, document->priv->indexed);
break;
case PROP_URI:
g_value_set_string (value, document->priv->doc_uri);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
document_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
YelpDocument *document = YELP_DOCUMENT (object);
switch (prop_id) {
case PROP_INDEXED:
document->priv->indexed = g_value_get_boolean (value);
if (document->priv->indexed)
g_idle_add ((GSourceFunc) document_indexed, document);
break;
case PROP_URI:
if (document->priv->doc_uri != NULL)
g_free (document->priv->doc_uri);
document->priv->doc_uri = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/******************************************************************************/
gchar **
......@@ -642,6 +736,20 @@ yelp_document_set_page_icon (YelpDocument *document,
g_mutex_unlock (document->priv->mutex);
}
static void
document_indexed (YelpDocument *document)
{
g_mutex_lock (document->priv->mutex);
while (document->priv->reqs_search != NULL) {
Request *request = (Request *) document->priv->reqs_search->data;
request->idle_funcs++;
g_idle_add ((GSourceFunc) request_idle_contents, request);
document->priv->reqs_search = g_slist_delete_link (document->priv->reqs_search,
document->priv->reqs_search);
}
g_mutex_unlock (document->priv->mutex);
}
/******************************************************************************/
gboolean
......@@ -693,6 +801,16 @@ document_request_page (YelpDocument *document,
g_mutex_lock (document->priv->mutex);
if (g_str_has_prefix (page_id, "search=")) {
document->priv->reqs_search = g_slist_prepend (document->priv->reqs_search, request);
if (document->priv->indexed)
g_idle_add ((GSourceFunc) document_indexed, document);
else
yelp_document_index (document);
g_mutex_unlock (document->priv->mutex);
return TRUE;
}
hash_slist_insert (document->priv->reqs_by_page_id,
request->page_id,
request);
......@@ -736,6 +854,48 @@ document_read_contents (YelpDocument *document,
g_mutex_lock (document->priv->mutex);
if (page_id != NULL && g_str_has_prefix (page_id, "search=")) {
gchar *tmp, *txt;
GVariant *value;
GVariantIter *iter;
gchar *url, *title, *desc, *icon; /* do not free */
GString *ret = g_string_new ("<html><body>");
str = hash_lookup (document->priv->contents, real);
if (str) {
str_ref (str);
g_mutex_unlock (document->priv->mutex);
return (const gchar *) str;
}
txt = g_uri_unescape_string (page_id + 7, NULL);
tmp = g_markup_printf_escaped ("<h1>Search results for “%s”</h1>", txt);
g_string_append (ret, tmp);
g_free (tmp);
value = yelp_storage_search (yelp_storage_get_default (),
document->priv->doc_uri,
txt);
iter = g_variant_iter_new (value);
while (g_variant_iter_loop (iter, "(&s&s&s&s)", &url, &title, &desc, &icon)) {
tmp = g_strdup_printf ("<div><a href='%s'>%s</a></div>", url, title);
g_string_append (ret, tmp);
g_free (tmp);
}
g_variant_iter_free (iter);
g_variant_unref (value);
g_free (txt);
g_string_append (ret, "</body></html>");
g_mutex_unlock (document->priv->mutex);
hash_replace (document->priv->contents, page_id, g_string_free (ret, FALSE));
str = hash_lookup (document->priv->contents, page_id);
str_ref (str);
g_mutex_unlock (document->priv->mutex);
return (const gchar *) str;
}
real = hash_lookup (document->priv->page_ids, page_id);
str = hash_lookup (document->priv->contents, real);
if (str)
......@@ -817,6 +977,23 @@ document_get_mime_type (YelpDocument *document,
/******************************************************************************/
void
yelp_document_index (YelpDocument *document)
{
g_return_if_fail (YELP_IS_DOCUMENT (document));
g_return_if_fail (YELP_DOCUMENT_GET_CLASS (document)->index != NULL);
YELP_DOCUMENT_GET_CLASS (document)->index (document);
}
static void
document_index (YelpDocument *document)
{
g_object_set (document, "indexed", TRUE, NULL);
}
/******************************************************************************/
void
yelp_document_signal (YelpDocument *document,
const gchar *page_id,
......@@ -994,6 +1171,7 @@ request_cancel (GCancellable *cancellable, Request *request)
{
GSList *cur;
YelpDocument *document = request->document;
gboolean found = FALSE;
g_assert (document != NULL && YELP_IS_DOCUMENT (document));
......@@ -1007,9 +1185,18 @@ request_cancel (GCancellable *cancellable, Request *request)
for (cur = document->priv->reqs_all; cur != NULL; cur = cur->next) {
if (cur->data == request) {
document->priv->reqs_all = g_slist_delete_link (document->priv->reqs_all, cur);
found = TRUE;
break;
}
}
if (!found) {
for (cur = document->priv->reqs_search; cur != NULL; cur = cur->next) {
if (cur->data == request) {
document->priv->reqs_search = g_slist_delete_link (document->priv->reqs_search, cur);
break;
}
}
}
request_try_free (request);
g_mutex_unlock (document->priv->mutex);
......
......@@ -71,7 +71,8 @@ struct _YelpDocumentClass {
void (*finish_read) (YelpDocument *document,
const gchar *contents);
gchar * (*get_mime_type) (YelpDocument *document,
const gchar *mime_type);
const gchar *page_id);
void (*index) (YelpDocument *document);
};
......@@ -96,6 +97,8 @@ const gchar * yelp_document_read_contents (YelpDocument *document,
void yelp_document_finish_read (YelpDocument *document,
const gchar *contents);
void yelp_document_index (YelpDocument *document);
gchar ** yelp_document_list_page_ids (YelpDocument *document);
gchar * yelp_document_get_page_id (YelpDocument *document,
......
......@@ -174,10 +174,15 @@ yelp_info_document_new (YelpUri *uri)
{
YelpInfoDocument *info;
YelpInfoDocumentPrivate *priv;
gchar *doc_uri;
g_return_val_if_fail (uri != NULL, NULL);
info = (YelpInfoDocument *) g_object_new (YELP_TYPE_INFO_DOCUMENT, NULL);
doc_uri = yelp_uri_get_document_uri (uri);
info = (YelpInfoDocument *) g_object_new (YELP_TYPE_INFO_DOCUMENT,
"document-uri", doc_uri,
NULL);
g_free (doc_uri);
priv = GET_PRIV (info);
priv->uri = g_object_ref (uri);
......
......@@ -611,7 +611,14 @@ location_entry_location_selected (YelpLocationEntry *entry)
static void
location_entry_search_activated (YelpLocationEntry *entry)
{
printf ("FIXME: search_activated\n");
YelpUri *base, *uri;
YelpLocationEntryPrivate *priv = GET_PRIV (entry);
g_object_get (priv->view, "yelp-uri", &base, NULL);
uri = yelp_uri_new_search (base,
gtk_entry_get_text (GTK_ENTRY (priv->text_entry)));
g_object_unref (base);
yelp_view_load_uri (priv->view, uri);
}
static void
......
......@@ -194,10 +194,15 @@ yelp_mallard_document_new (YelpUri *uri)
{
YelpMallardDocument *mallard;
YelpMallardDocumentPrivate *priv;
gchar *doc_uri;
g_return_val_if_fail (uri != NULL, NULL);
mallard = (YelpMallardDocument *) g_object_new (YELP_TYPE_MALLARD_DOCUMENT, NULL);
doc_uri = yelp_uri_get_document_uri (uri);
mallard = (YelpMallardDocument *) g_object_new (YELP_TYPE_MALLARD_DOCUMENT,
"document-uri", doc_uri,
NULL);
g_free (doc_uri);
priv = GET_PRIV (mallard);
priv->uri = g_object_ref (uri);
......
......@@ -209,10 +209,15 @@ yelp_man_document_new (YelpUri *uri)
{
YelpManDocument *man;
YelpManDocumentPrivate *priv;
gchar *doc_uri;
g_return_val_if_fail (uri != NULL, NULL);
man = (YelpManDocument *) g_object_new (YELP_TYPE_MAN_DOCUMENT, NULL);
doc_uri = yelp_uri_get_document_uri (uri);
man = (YelpManDocument *) g_object_new (YELP_TYPE_MAN_DOCUMENT,
"document-uri", doc_uri,
NULL);
g_free (doc_uri);
priv = GET_PRIV (man);
priv->uri = g_object_ref (uri);
......
......@@ -166,8 +166,13 @@ YelpDocument *
yelp_simple_document_new (YelpUri *uri)
{
YelpSimpleDocument *document;
gchar *doc_uri;
document = (YelpSimpleDocument *) g_object_new (YELP_TYPE_SIMPLE_DOCUMENT, NULL);
doc_uri = yelp_uri_get_document_uri (uri);
document = (YelpSimpleDocument *) g_object_new (YELP_TYPE_SIMPLE_DOCUMENT,
"document-uri", doc_uri,
NULL);
g_free (doc_uri);
document->priv->file = yelp_uri_get_file (uri);
......
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2011 Shaun McCance <shaunm@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Shaun McCance <shaunm@gnome.org>
*/
#include "config.h"
#include <glib/gi18n.h>
#include <sqlite3.h>
#include "yelp-sqlite-storage.h"
static void yelp_sqlite_storage_init (YelpSqliteStorage *storage);
static void yelp_sqlite_storage_class_init (YelpSqliteStorageClass *klass);
static void yelp_sqlite_storage_iface_init (YelpStorageInterface *iface);
static void yelp_sqlite_storage_finalize (GObject *object);
static void yelp_sqlite_storage_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void yelp_sqlite_storage_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void yelp_sqlite_storage_update (YelpStorage *storage,
const gchar *doc_uri,
const gchar *full_uri,
const gchar *title,
const gchar *desc,
const gchar *icon,
const gchar *text);
static GVariant * yelp_sqlite_storage_search (YelpStorage *storage,
const gchar *doc_uri,
const gchar *text);
typedef struct _YelpSqliteStoragePrivate YelpSqliteStoragePrivate;
struct _YelpSqliteStoragePrivate {
gchar *filename;
sqlite3 *db;
};
enum {
PROP_0,
PROP_FILENAME
};
G_DEFINE_TYPE_WITH_CODE (YelpSqliteStorage, yelp_sqlite_storage, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (YELP_TYPE_STORAGE,
yelp_sqlite_storage_iface_init))
#define GET_PRIV(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_SQLITE_STORAGE, YelpSqliteStoragePrivate))
static void
yelp_sqlite_storage_finalize (GObject *object)
{
YelpSqliteStoragePrivate *priv = GET_PRIV (object);
if (priv->filename)
g_free (priv->filename);
if (priv->db)
sqlite3_close (priv->db);
G_OBJECT_CLASS (yelp_sqlite_storage_parent_class)->finalize (object);
}
static void
yelp_sqlite_storage_init (YelpSqliteStorage *storage)
{
}
static void
yelp_sqlite_storage_constructed (GObject *object)
{
YelpSqliteStoragePrivate *priv = GET_PRIV (object);
if (priv->filename != NULL)
sqlite3_open (priv->filename, &(priv->db));
else
sqlite3_open (":memory:", &(priv->db));
/* FIXME: create tables if necessary */
}
static void
yelp_sqlite_storage_class_init (YelpSqliteStorageClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = yelp_sqlite_storage_constructed;
object_class->finalize = yelp_sqlite_storage_finalize;
object_class->get_property = yelp_sqlite_storage_get_property;
object_class->set_property = yelp_sqlite_storage_set_property;
g_type_class_add_private (klass, sizeof (YelpSqliteStoragePrivate));
g_object_class_install_property (object_class,
PROP_FILENAME,
g_param_spec_string ("filename",
N_("Database filename"),
N_("The filename of the sqlite database"),
NULL,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
}
static void
yelp_sqlite_storage_iface_init (YelpStorageInterface *iface)