|
Packit |
116408 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
|
|
Packit |
116408 |
/*
|
|
Packit |
116408 |
* Copyright (C) 2002 CodeFactory AB
|
|
Packit |
116408 |
* Copyright (C) 2002 Mikael Hallendal <micke@imendio.com>
|
|
Packit |
116408 |
* Copyright (C) 2004-2008 Imendio AB
|
|
Packit |
116408 |
* Copyright (C) 2010 Lanedo GmbH
|
|
Packit |
116408 |
* Copyright (C) 2017, 2018 Sébastien Wilmet <swilmet@gnome.org>
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* This program is free software; you can redistribute it and/or
|
|
Packit |
116408 |
* modify it under the terms of the GNU General Public License as
|
|
Packit |
116408 |
* published by the Free Software Foundation; either version 2 of the
|
|
Packit |
116408 |
* License, or (at your option) any later version.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
116408 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
116408 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
116408 |
* General Public License for more details.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
116408 |
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
|
|
Packit |
116408 |
#include "config.h"
|
|
Packit |
116408 |
#include "dh-book.h"
|
|
Packit |
116408 |
#include <glib/gi18n-lib.h>
|
|
Packit |
116408 |
#include "dh-link.h"
|
|
Packit |
116408 |
#include "dh-parser.h"
|
|
Packit |
116408 |
#include "dh-util.h"
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* SECTION:dh-book
|
|
Packit |
116408 |
* @Title: DhBook
|
|
Packit |
116408 |
* @Short_description: A book, usually the documentation for one library
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* A #DhBook usually contains the documentation for one library (or
|
|
Packit |
116408 |
* application), for example GLib or GTK+. A #DhBook corresponds to one index
|
|
Packit |
116408 |
* file. An index file is a file with the extension `*.devhelp`, `*.devhelp2`,
|
|
Packit |
116408 |
* `*.devhelp.gz` or `*.devhelp2.gz`.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* #DhBook creates a #GFileMonitor on the index file, and emits the
|
|
Packit |
116408 |
* #DhBook::updated or #DhBook::deleted signal in case the index file has
|
|
Packit |
116408 |
* changed on the filesystem. #DhBookManager listens to those #DhBook signals,
|
|
Packit |
116408 |
* and emits in turn the #DhBookManager::book-deleted and
|
|
Packit |
116408 |
* #DhBookManager::book-created signals.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* Timeout to wait for new events on the index file so that they are merged and
|
|
Packit |
116408 |
* we don't spam unneeded signals.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
#define EVENT_MERGE_TIMEOUT_SECS (2)
|
|
Packit |
116408 |
|
|
Packit |
116408 |
enum {
|
|
Packit |
116408 |
/* FIXME: a boolean property would be a better API instead of the
|
|
Packit |
116408 |
* ::enabled and ::disabled signals. Or this whole concept can be
|
|
Packit |
116408 |
* removed from DhBook, by introducing DhBookSelection, see:
|
|
Packit |
116408 |
* https://bugzilla.gnome.org/show_bug.cgi?id=784491#c3
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
SIGNAL_ENABLED,
|
|
Packit |
116408 |
SIGNAL_DISABLED,
|
|
Packit |
116408 |
|
|
Packit |
116408 |
SIGNAL_UPDATED,
|
|
Packit |
116408 |
SIGNAL_DELETED,
|
|
Packit |
116408 |
N_SIGNALS
|
|
Packit |
116408 |
};
|
|
Packit |
116408 |
|
|
Packit |
116408 |
typedef enum {
|
|
Packit |
116408 |
BOOK_MONITOR_EVENT_NONE,
|
|
Packit |
116408 |
BOOK_MONITOR_EVENT_UPDATED,
|
|
Packit |
116408 |
BOOK_MONITOR_EVENT_DELETED
|
|
Packit |
116408 |
} BookMonitorEvent;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
typedef struct {
|
|
Packit |
116408 |
GFile *index_file;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
gchar *id;
|
|
Packit |
116408 |
gchar *title;
|
|
Packit |
116408 |
gchar *language;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* The book tree of DhLink*. */
|
|
Packit |
116408 |
GNode *tree;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* List of DhLink*. */
|
|
Packit |
116408 |
GList *links;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
DhCompletion *completion;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
GFileMonitor *index_file_monitor;
|
|
Packit |
116408 |
BookMonitorEvent last_monitor_event;
|
|
Packit |
116408 |
guint monitor_event_timeout_id;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
guint enabled : 1;
|
|
Packit |
116408 |
} DhBookPrivate;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
G_DEFINE_TYPE_WITH_PRIVATE (DhBook, dh_book, G_TYPE_OBJECT);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
static guint signals[N_SIGNALS] = { 0 };
|
|
Packit |
116408 |
|
|
Packit |
116408 |
static void
|
|
Packit |
116408 |
dh_book_dispose (GObject *object)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (DH_BOOK (object));
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_clear_object (&priv->completion);
|
|
Packit |
116408 |
g_clear_object (&priv->index_file_monitor);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
if (priv->monitor_event_timeout_id != 0) {
|
|
Packit |
116408 |
g_source_remove (priv->monitor_event_timeout_id);
|
|
Packit |
116408 |
priv->monitor_event_timeout_id = 0;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
G_OBJECT_CLASS (dh_book_parent_class)->dispose (object);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
static void
|
|
Packit |
116408 |
dh_book_finalize (GObject *object)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (DH_BOOK (object));
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_clear_object (&priv->index_file);
|
|
Packit |
116408 |
g_free (priv->id);
|
|
Packit |
116408 |
g_free (priv->title);
|
|
Packit |
116408 |
g_free (priv->language);
|
|
Packit |
116408 |
_dh_util_free_book_tree (priv->tree);
|
|
Packit |
116408 |
g_list_free_full (priv->links, (GDestroyNotify)dh_link_unref);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
G_OBJECT_CLASS (dh_book_parent_class)->finalize (object);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
static void
|
|
Packit |
116408 |
dh_book_class_init (DhBookClass *klass)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
object_class->dispose = dh_book_dispose;
|
|
Packit |
116408 |
object_class->finalize = dh_book_finalize;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* DhBook::enabled:
|
|
Packit |
116408 |
* @book: the #DhBook emitting the signal.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
signals[SIGNAL_ENABLED] =
|
|
Packit |
116408 |
g_signal_new ("enabled",
|
|
Packit |
116408 |
G_TYPE_FROM_CLASS (klass),
|
|
Packit |
116408 |
G_SIGNAL_RUN_LAST,
|
|
Packit |
116408 |
0,
|
|
Packit |
116408 |
NULL, NULL, NULL,
|
|
Packit |
116408 |
G_TYPE_NONE,
|
|
Packit |
116408 |
0);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* DhBook::disabled:
|
|
Packit |
116408 |
* @book: the #DhBook emitting the signal.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
signals[SIGNAL_DISABLED] =
|
|
Packit |
116408 |
g_signal_new ("disabled",
|
|
Packit |
116408 |
G_TYPE_FROM_CLASS (klass),
|
|
Packit |
116408 |
G_SIGNAL_RUN_LAST,
|
|
Packit |
116408 |
0,
|
|
Packit |
116408 |
NULL, NULL, NULL,
|
|
Packit |
116408 |
G_TYPE_NONE,
|
|
Packit |
116408 |
0);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* DhBook::updated:
|
|
Packit |
116408 |
* @book: the #DhBook emitting the signal.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* The ::updated signal is emitted when the index file has been
|
|
Packit |
116408 |
* modified (but the file still exists).
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
signals[SIGNAL_UPDATED] =
|
|
Packit |
116408 |
g_signal_new ("updated",
|
|
Packit |
116408 |
G_TYPE_FROM_CLASS (klass),
|
|
Packit |
116408 |
G_SIGNAL_RUN_LAST,
|
|
Packit |
116408 |
0,
|
|
Packit |
116408 |
NULL, NULL, NULL,
|
|
Packit |
116408 |
G_TYPE_NONE,
|
|
Packit |
116408 |
0);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* DhBook::deleted:
|
|
Packit |
116408 |
* @book: the #DhBook emitting the signal.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* The ::deleted signal is emitted when the index file has been deleted
|
|
Packit |
116408 |
* from the filesystem.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
signals[SIGNAL_DELETED] =
|
|
Packit |
116408 |
g_signal_new ("deleted",
|
|
Packit |
116408 |
G_TYPE_FROM_CLASS (klass),
|
|
Packit |
116408 |
G_SIGNAL_RUN_LAST,
|
|
Packit |
116408 |
0,
|
|
Packit |
116408 |
NULL, NULL, NULL,
|
|
Packit |
116408 |
G_TYPE_NONE,
|
|
Packit |
116408 |
0);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
static void
|
|
Packit |
116408 |
dh_book_init (DhBook *book)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv->enabled = TRUE;
|
|
Packit |
116408 |
priv->last_monitor_event = BOOK_MONITOR_EVENT_NONE;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
static gboolean
|
|
Packit |
116408 |
monitor_event_timeout_cb (gpointer data)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBook *book = DH_BOOK (data);
|
|
Packit |
116408 |
DhBookPrivate *priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
BookMonitorEvent last_monitor_event = priv->last_monitor_event;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* Reset event */
|
|
Packit |
116408 |
priv->last_monitor_event = BOOK_MONITOR_EVENT_NONE;
|
|
Packit |
116408 |
priv->monitor_event_timeout_id = 0;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* We'll get either is_deleted OR is_updated, not possible to have both
|
|
Packit |
116408 |
* or none.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
switch (last_monitor_event)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
case BOOK_MONITOR_EVENT_DELETED:
|
|
Packit |
116408 |
/* Emit the signal, but make sure we hold a reference while
|
|
Packit |
116408 |
* doing it.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
g_object_ref (book);
|
|
Packit |
116408 |
g_signal_emit (book, signals[SIGNAL_DELETED], 0);
|
|
Packit |
116408 |
g_object_unref (book);
|
|
Packit |
116408 |
break;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
case BOOK_MONITOR_EVENT_UPDATED:
|
|
Packit |
116408 |
/* Emit the signal, but make sure we hold a reference while
|
|
Packit |
116408 |
* doing it.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
g_object_ref (book);
|
|
Packit |
116408 |
g_signal_emit (book, signals[SIGNAL_UPDATED], 0);
|
|
Packit |
116408 |
g_object_unref (book);
|
|
Packit |
116408 |
break;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
case BOOK_MONITOR_EVENT_NONE:
|
|
Packit |
116408 |
default:
|
|
Packit |
116408 |
break;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* book can be destroyed here. */
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return G_SOURCE_REMOVE;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
static void
|
|
Packit |
116408 |
index_file_changed_cb (GFileMonitor *file_monitor,
|
|
Packit |
116408 |
GFile *file,
|
|
Packit |
116408 |
GFile *other_file,
|
|
Packit |
116408 |
GFileMonitorEvent event_type,
|
|
Packit |
116408 |
DhBook *book)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
gboolean reset_timeout = FALSE;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* CREATED may happen if the file is deleted and then created right
|
|
Packit |
116408 |
* away, as we're merging events.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
|
|
Packit |
116408 |
event_type == G_FILE_MONITOR_EVENT_CREATED) {
|
|
Packit |
116408 |
priv->last_monitor_event = BOOK_MONITOR_EVENT_UPDATED;
|
|
Packit |
116408 |
reset_timeout = TRUE;
|
|
Packit |
116408 |
} else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
|
|
Packit |
116408 |
priv->last_monitor_event = BOOK_MONITOR_EVENT_DELETED;
|
|
Packit |
116408 |
reset_timeout = TRUE;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
if (reset_timeout) {
|
|
Packit |
116408 |
if (priv->monitor_event_timeout_id != 0)
|
|
Packit |
116408 |
g_source_remove (priv->monitor_event_timeout_id);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv->monitor_event_timeout_id = g_timeout_add_seconds (EVENT_MERGE_TIMEOUT_SECS,
|
|
Packit |
116408 |
monitor_event_timeout_cb,
|
|
Packit |
116408 |
book);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_new:
|
|
Packit |
116408 |
* @index_file: the index file.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: (nullable): a new #DhBook object, or %NULL if parsing the index file
|
|
Packit |
116408 |
* failed.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
DhBook *
|
|
Packit |
116408 |
dh_book_new (GFile *index_file)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
DhBook *book;
|
|
Packit |
116408 |
gchar *language = NULL;
|
|
Packit |
116408 |
GError *error = NULL;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_return_val_if_fail (G_IS_FILE (index_file), NULL);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
book = g_object_new (DH_TYPE_BOOK, NULL);
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv->index_file = g_object_ref (index_file);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* Parse file storing contents in the book struct. */
|
|
Packit |
116408 |
if (!dh_parser_read_file (priv->index_file,
|
|
Packit |
116408 |
&priv->title,
|
|
Packit |
116408 |
&priv->id,
|
|
Packit |
116408 |
&language,
|
|
Packit |
116408 |
&priv->tree,
|
|
Packit |
116408 |
&priv->links,
|
|
Packit |
116408 |
&error)) {
|
|
Packit |
116408 |
/* It's fine if the file doesn't exist, as DhBookManager tries
|
|
Packit |
116408 |
* to create a DhBook for each possible index file in a certain
|
|
Packit |
116408 |
* book directory.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
if (error != NULL &&
|
|
Packit |
116408 |
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
|
|
Packit |
116408 |
gchar *parse_name;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
parse_name = g_file_get_parse_name (priv->index_file);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_warning ("Failed to read “%s”: %s",
|
|
Packit |
116408 |
parse_name,
|
|
Packit |
116408 |
error->message);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_free (parse_name);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_clear_error (&error);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* Deallocate the book, as we are not going to add it in the
|
|
Packit |
116408 |
* manager.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
g_object_unref (book);
|
|
Packit |
116408 |
return NULL;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* Rewrite language, if any, including the prefix we want to use when
|
|
Packit |
116408 |
* seeing it, to standarize how the language group is shown.
|
|
Packit |
116408 |
* FIXME: maybe instead of a string, have a DhLanguage object which
|
|
Packit |
116408 |
* canonicalizes the string.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
dh_util_ascii_strtitle (language);
|
|
Packit |
116408 |
priv->language = (language != NULL ?
|
|
Packit |
116408 |
g_strdup_printf (_("Language: %s"), language) :
|
|
Packit |
116408 |
g_strdup (_("Language: Undefined")));
|
|
Packit |
116408 |
g_free (language);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* Setup monitor for changes */
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv->index_file_monitor = g_file_monitor_file (priv->index_file,
|
|
Packit |
116408 |
G_FILE_MONITOR_NONE,
|
|
Packit |
116408 |
NULL,
|
|
Packit |
116408 |
&error);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
if (error != NULL) {
|
|
Packit |
116408 |
gchar *parse_name;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
parse_name = g_file_get_parse_name (priv->index_file);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_warning ("Failed to create file monitor for file “%s”: %s",
|
|
Packit |
116408 |
parse_name,
|
|
Packit |
116408 |
error->message);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_free (parse_name);
|
|
Packit |
116408 |
g_clear_error (&error);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
if (priv->index_file_monitor != NULL) {
|
|
Packit |
116408 |
g_signal_connect_object (priv->index_file_monitor,
|
|
Packit |
116408 |
"changed",
|
|
Packit |
116408 |
G_CALLBACK (index_file_changed_cb),
|
|
Packit |
116408 |
book,
|
|
Packit |
116408 |
0);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return book;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_get_index_file:
|
|
Packit |
116408 |
* @book: a #DhBook.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: (transfer none): the index file.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
GFile *
|
|
Packit |
116408 |
dh_book_get_index_file (DhBook *book)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_return_val_if_fail (DH_IS_BOOK (book), NULL);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return priv->index_file;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_get_id:
|
|
Packit |
116408 |
* @book: a #DhBook.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Gets the book ID. In the Devhelp index file format version 2, it is actually
|
|
Packit |
116408 |
* the “name”, not the ID, but “book ID” is clearer, “book name” can be confused
|
|
Packit |
116408 |
* with the title.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: the book ID.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
const gchar *
|
|
Packit |
116408 |
dh_book_get_id (DhBook *book)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_return_val_if_fail (DH_IS_BOOK (book), NULL);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return priv->id;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_get_title:
|
|
Packit |
116408 |
* @book: a #DhBook.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: the book title.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
const gchar *
|
|
Packit |
116408 |
dh_book_get_title (DhBook *book)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_return_val_if_fail (DH_IS_BOOK (book), NULL);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return priv->title;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_get_language:
|
|
Packit |
116408 |
* @book: a #DhBook.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: the programming language used in @book.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
const gchar *
|
|
Packit |
116408 |
dh_book_get_language (DhBook *book)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_return_val_if_fail (DH_IS_BOOK (book), NULL);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return priv->language;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_get_links:
|
|
Packit |
116408 |
* @book: a #DhBook.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: (element-type DhLink) (transfer none) (nullable): the list of
|
|
Packit |
116408 |
* <emphasis>all</emphasis> #DhLink's part of @book, or %NULL if the book is
|
|
Packit |
116408 |
* disabled.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
GList *
|
|
Packit |
116408 |
dh_book_get_links (DhBook *book)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_return_val_if_fail (DH_IS_BOOK (book), NULL);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return priv->enabled ? priv->links : NULL;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_get_tree:
|
|
Packit |
116408 |
* @book: a #DhBook.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Gets the general structure of the book, as a tree. The tree contains only
|
|
Packit |
116408 |
* #DhLink's of type %DH_LINK_TYPE_BOOK or %DH_LINK_TYPE_PAGE. The other
|
|
Packit |
116408 |
* #DhLink's are not contained in the tree. To have a list of
|
|
Packit |
116408 |
* <emphasis>all</emphasis> #DhLink's part of the book, you need to call
|
|
Packit |
116408 |
* dh_book_get_links().
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: (transfer none) (nullable): the tree of #DhLink's part of the @book,
|
|
Packit |
116408 |
* or %NULL if the book is disabled.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
GNode *
|
|
Packit |
116408 |
dh_book_get_tree (DhBook *book)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_return_val_if_fail (DH_IS_BOOK (book), NULL);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return priv->enabled ? priv->tree : NULL;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_get_completion:
|
|
Packit |
116408 |
* @book: a #DhBook.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: (transfer none): the #DhCompletion of @book.
|
|
Packit |
116408 |
* Since: 3.28
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
DhCompletion *
|
|
Packit |
116408 |
dh_book_get_completion (DhBook *book)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_return_val_if_fail (DH_IS_BOOK (book), NULL);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
if (priv->completion == NULL) {
|
|
Packit |
116408 |
GList *l;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv->completion = dh_completion_new ();
|
|
Packit |
116408 |
|
|
Packit |
116408 |
for (l = priv->links; l != NULL; l = l->next) {
|
|
Packit |
116408 |
DhLink *link = l->data;
|
|
Packit |
116408 |
const gchar *str;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* Do not provide completion for book titles. Normally
|
|
Packit |
116408 |
* the user doesn't need it, it's more convenient to
|
|
Packit |
116408 |
* choose a book with the DhBookTree.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
if (dh_link_get_link_type (link) == DH_LINK_TYPE_BOOK)
|
|
Packit |
116408 |
continue;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
str = dh_link_get_name (link);
|
|
Packit |
116408 |
dh_completion_add_string (priv->completion, str);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
dh_completion_sort (priv->completion);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return priv->completion;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_get_enabled:
|
|
Packit |
116408 |
* @book: a #DhBook.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: whether the book is enabled.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
gboolean
|
|
Packit |
116408 |
dh_book_get_enabled (DhBook *book)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_return_val_if_fail (DH_IS_BOOK (book), FALSE);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return priv->enabled;
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_set_enabled:
|
|
Packit |
116408 |
* @book: a #DhBook.
|
|
Packit |
116408 |
* @enabled: the new value.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Enables or disables the book.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
void
|
|
Packit |
116408 |
dh_book_set_enabled (DhBook *book,
|
|
Packit |
116408 |
gboolean enabled)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
g_return_if_fail (DH_IS_BOOK (book));
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv = dh_book_get_instance_private (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
enabled = enabled != FALSE;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/* Create DhCompletion, because if all the DhCompletion objects need to
|
|
Packit |
116408 |
* be created (synchronously) at the time of the first completion, it
|
|
Packit |
116408 |
* can make the GUI not responsive (measured time was for example 40ms
|
|
Packit |
116408 |
* to create the DhCompletion's for 17 books, which is not a lot of
|
|
Packit |
116408 |
* books). On application startup it is less a problem.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
if (enabled)
|
|
Packit |
116408 |
dh_book_get_completion (book);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
if (priv->enabled != enabled) {
|
|
Packit |
116408 |
priv->enabled = enabled;
|
|
Packit |
116408 |
g_signal_emit (book,
|
|
Packit |
116408 |
enabled ? signals[SIGNAL_ENABLED] : signals[SIGNAL_DISABLED],
|
|
Packit |
116408 |
0);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_cmp_by_id:
|
|
Packit |
116408 |
* @a: a #DhBook.
|
|
Packit |
116408 |
* @b: a #DhBook.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Compares the #DhBook's by their IDs, with g_ascii_strcasecmp().
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: an integer less than, equal to, or greater than zero, if @a is <, ==
|
|
Packit |
116408 |
* or > than @b.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
gint
|
|
Packit |
116408 |
dh_book_cmp_by_id (DhBook *a,
|
|
Packit |
116408 |
DhBook *b)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv_a;
|
|
Packit |
116408 |
DhBookPrivate *priv_b;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
if (a == NULL || b == NULL)
|
|
Packit |
116408 |
return -1;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv_a = dh_book_get_instance_private (a);
|
|
Packit |
116408 |
priv_b = dh_book_get_instance_private (b);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
if (priv_a->id == NULL || priv_b->id == NULL)
|
|
Packit |
116408 |
return -1;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return g_ascii_strcasecmp (priv_a->id, priv_b->id);
|
|
Packit |
116408 |
}
|
|
Packit |
116408 |
|
|
Packit |
116408 |
/**
|
|
Packit |
116408 |
* dh_book_cmp_by_title:
|
|
Packit |
116408 |
* @a: a #DhBook.
|
|
Packit |
116408 |
* @b: a #DhBook.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Compares the #DhBook's by their title.
|
|
Packit |
116408 |
*
|
|
Packit |
116408 |
* Returns: an integer less than, equal to, or greater than zero, if @a is <, ==
|
|
Packit |
116408 |
* or > than @b.
|
|
Packit |
116408 |
*/
|
|
Packit |
116408 |
gint
|
|
Packit |
116408 |
dh_book_cmp_by_title (DhBook *a,
|
|
Packit |
116408 |
DhBook *b)
|
|
Packit |
116408 |
{
|
|
Packit |
116408 |
DhBookPrivate *priv_a;
|
|
Packit |
116408 |
DhBookPrivate *priv_b;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
if (a == NULL || b == NULL)
|
|
Packit |
116408 |
return -1;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
priv_a = dh_book_get_instance_private (a);
|
|
Packit |
116408 |
priv_b = dh_book_get_instance_private (b);
|
|
Packit |
116408 |
|
|
Packit |
116408 |
if (priv_a->title == NULL || priv_b->title == NULL)
|
|
Packit |
116408 |
return -1;
|
|
Packit |
116408 |
|
|
Packit |
116408 |
return g_utf8_collate (priv_a->title, priv_b->title);
|
|
Packit |
116408 |
}
|