Move XBEL implementation to katze.

The implementation of XBEL is moved to katze, including the
appropriate api prefix and coding style changes. All relevant
uses are updated.
This commit is contained in:
Christian Dywan 2008-01-06 01:44:37 +01:00
parent e2328a4bfc
commit d5a4f4cfd7
13 changed files with 1292 additions and 1141 deletions

View File

@ -1,13 +1,16 @@
INCLUDES = \
$(GTK_CFLAGS)
$(GTK_CFLAGS) \
$(LIBXML_CFLAGS)
noinst_LTLIBRARIES = \
libkatze.la
libkatze_la_LIBADD = \
$(GTK_LIBS)
$(GTK_LIBS) \
$(LIBXML_LIBS)
libkatze_la_SOURCES = \
katze.h \
katze-throbber.c katze-throbber.h \
katze-utils.c katze-utils.h
katze-utils.c katze-utils.h \
katze-xbel.c katze-xbel.h

958
katze/katze-xbel.c Normal file
View File

@ -0,0 +1,958 @@
/*
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
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.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
/**
* TODO:
* - Support info > metadata, alias, added, modified, visited
* - Compatibility: The Nokia 770 *requires* metadata and folder
* - Compatibility: Kazehakase's bookmarks
* - Compatibility: Epiphany's bookmarks
* - XML Indentation
**/
#include "katze-xbel.h"
#include <stdio.h>
#include <string.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include "katze-utils.h"
struct _KatzeXbelItemPrivate
{
guint refs;
KatzeXbelItemKind kind;
KatzeXbelItem* parent;
GList* items; // folder
gboolean folded; // foolder
gchar* title; // !separator
gchar* desc; // folder and bookmark
gchar* href; // bookmark
//time_t added; // !separator
//time_t modfied; // bookmark
//time_t visited; // bookmark
} ;
#define KATZE_XBEL_ITEM_GET_PRIVATE(item) \
item->priv
// Private: Create a new item of a certain type
static KatzeXbelItem*
katze_xbel_item_new (KatzeXbelItemKind kind)
{
KatzeXbelItem* item = g_new (KatzeXbelItem, 1);
KATZE_XBEL_ITEM_GET_PRIVATE (item) = g_new (KatzeXbelItemPrivate, 1);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
priv->refs = 1;
priv->parent = NULL;
priv->kind = kind;
if (kind == KATZE_XBEL_ITEM_KIND_FOLDER)
{
priv->items = NULL;
priv->folded = TRUE;
}
if (kind != KATZE_XBEL_ITEM_KIND_SEPARATOR)
{
priv->title = NULL;
priv->desc = NULL;
}
if (kind == KATZE_XBEL_ITEM_KIND_BOOKMARK)
priv->href = g_strdup ("");
return item;
}
/**
* katze_xbel_bookmark_new:
*
* Create a new empty bookmark.
*
* Return value: a newly allocated bookmark
**/
KatzeXbelItem*
katze_xbel_bookmark_new (void)
{
return katze_xbel_item_new (KATZE_XBEL_ITEM_KIND_BOOKMARK);
}
static KatzeXbelItem*
katze_xbel_bookmark_from_xmlNodePtr (xmlNodePtr cur)
{
g_return_val_if_fail (cur, NULL);
KatzeXbelItem* bookmark = katze_xbel_bookmark_new ();
xmlChar* key = xmlGetProp (cur, (xmlChar*)"href");
katze_xbel_bookmark_set_href (bookmark, (gchar*)key);
cur = cur->xmlChildrenNode;
while (cur)
{
if (!xmlStrcmp (cur->name, (const xmlChar*)"title"))
{
xmlChar* key = xmlNodeGetContent (cur);
katze_xbel_item_set_title (bookmark, g_strstrip ((gchar*)key));
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"desc"))
{
xmlChar* key = xmlNodeGetContent (cur);
katze_xbel_item_set_desc (bookmark, g_strstrip ((gchar*)key));
}
cur = cur->next;
}
return bookmark;
}
/**
* katze_katze_xbel_separator_new:
*
* Create a new separator.
*
* The returned item must be freed eventually.
*
* Return value: a newly allocated separator.
**/
KatzeXbelItem*
katze_xbel_separator_new (void)
{
return katze_xbel_item_new (KATZE_XBEL_ITEM_KIND_SEPARATOR);
}
/**
* katze_xbel_folder_new:
*
* Create a new empty folder.
*
* The returned item must be freed eventually.
*
* Return value: a newly allocated folder.
**/
KatzeXbelItem*
katze_xbel_folder_new (void)
{
return katze_xbel_item_new (KATZE_XBEL_ITEM_KIND_FOLDER);
}
// Private: Create a folder from an xmlNodePtr
static KatzeXbelItem*
katze_xbel_folder_from_xmlNodePtr (xmlNodePtr cur)
{
g_return_val_if_fail (cur, NULL);
KatzeXbelItem* folder = katze_xbel_folder_new ();
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (folder);
xmlChar* key = xmlGetProp (cur, (xmlChar*)"folded");
if (key)
{
if (!g_ascii_strncasecmp ((gchar*)key, "yes", 3))
priv->folded = TRUE;
else if (!g_ascii_strncasecmp ((gchar*)key, "no", 2))
priv->folded = FALSE;
else
g_warning ("XBEL: Unknown value for folded.");
xmlFree (key);
}
cur = cur->xmlChildrenNode;
while (cur)
{
if (!xmlStrcmp (cur->name, (const xmlChar*)"title"))
{
xmlChar* key = xmlNodeGetContent (cur);
katze_assign (priv->title, g_strstrip ((gchar*)key));
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"desc"))
{
xmlChar* key = xmlNodeGetContent (cur);
katze_assign (priv->desc, g_strstrip ((gchar*)key));
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"folder"))
{
KatzeXbelItem* item = katze_xbel_folder_from_xmlNodePtr (cur);
KATZE_XBEL_ITEM_GET_PRIVATE (item)->parent = folder;
priv->items = g_list_prepend (priv->items, item);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"bookmark"))
{
KatzeXbelItem* item = katze_xbel_bookmark_from_xmlNodePtr (cur);
priv->parent = folder;
priv->items = g_list_prepend (priv->items, item);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"separator"))
{
KatzeXbelItem* item = katze_xbel_separator_new ();
priv->parent = folder;
priv->items = g_list_prepend (priv->items, item);
}
cur = cur->next;
}
// Prepending and reversing is faster than appending
priv->items = g_list_reverse (priv->items);
return folder;
}
// Private: Loads the contents from an xmlNodePtr into a folder.
static gboolean
katze_xbel_folder_from_xmlDocPtr (KatzeXbelItem* folder,
xmlDocPtr doc)
{
g_return_val_if_fail (katze_xbel_folder_is_empty (folder), FALSE);
g_return_val_if_fail (doc, FALSE);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (folder);
xmlNodePtr cur = xmlDocGetRootElement (doc);
xmlChar* version = xmlGetProp (cur, (xmlChar*)"version");
if (xmlStrcmp (version, (xmlChar*)"1.0"))
g_warning ("XBEL version is not 1.0.");
xmlFree (version);
katze_assign (priv->title, (gchar*)xmlGetProp (cur, (xmlChar*)"title"));
katze_assign (priv->desc, (gchar*)xmlGetProp (cur, (xmlChar*)"desc"));
if ((cur = xmlDocGetRootElement (doc)) == NULL)
{
// Empty document
return FALSE;
}
if (xmlStrcmp (cur->name, (const xmlChar*)"xbel"))
{
// Wrong document kind
return FALSE;
}
cur = cur->xmlChildrenNode;
while (cur)
{
KatzeXbelItem* item = NULL;
if (!xmlStrcmp (cur->name, (const xmlChar*)"folder"))
item = katze_xbel_folder_from_xmlNodePtr (cur);
else if (!xmlStrcmp (cur->name, (const xmlChar*)"bookmark"))
item = katze_xbel_bookmark_from_xmlNodePtr (cur);
else if (!xmlStrcmp (cur->name, (const xmlChar*)"separator"))
item = katze_xbel_separator_new ();
/*else if (!xmlStrcmp (cur->name, (const xmlChar*)"info"))
item = katze_xbel_parse_info (xbel, cur);*/
if (item)
{
KATZE_XBEL_ITEM_GET_PRIVATE (item)->parent = folder;
priv->items = g_list_prepend (priv->items, item);
}
cur = cur->next;
}
// Prepending and reversing is faster than appending
priv->items = g_list_reverse (priv->items);
return TRUE;
}
/**
* katze_xbel_item_ref:
* @item: a valid item
*
* Ref an KatzeXbelItem.
*
* Ref means that the reference count is increased by one.
*
* This has no effect on children of a folder.
**/
void
katze_xbel_item_ref (KatzeXbelItem* item)
{
g_return_if_fail (item);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
priv->refs++;
}
/**
* katze_xbel_item_unref:
* @item: a valid item
*
* Unref an KatzeXbelItem. If @item is a folder all of its children will also
* be unreffed automatically.
*
* Unref means that the reference count is decreased. If there are no
* references left, the memory will be freed and if needed removed from
* its containing folder.
**/
void
katze_xbel_item_unref (KatzeXbelItem* item)
{
g_return_if_fail (item);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
priv->refs--;
if (priv->refs)
return;
if (priv->parent)
katze_xbel_folder_remove_item (priv->parent, item);
if (priv->kind == KATZE_XBEL_ITEM_KIND_FOLDER)
{
guint n = katze_xbel_folder_get_n_items (item);
guint i;
for (i = 0; i < n; i++)
{
KatzeXbelItem* _item = katze_xbel_folder_get_nth_item (item, i);
KATZE_XBEL_ITEM_GET_PRIVATE (_item)->parent = NULL;
katze_xbel_item_unref (_item);
}
g_list_free (priv->items);
}
if (priv->kind != KATZE_XBEL_ITEM_KIND_SEPARATOR)
{
g_free (priv->title);
g_free (priv->desc);
}
if (priv->kind == KATZE_XBEL_ITEM_KIND_BOOKMARK)
g_free (priv->href);
g_free (item);
}
/**
* katze_xbel_item_copy:
* @item: the item to copy
*
* Copy an KatzeXbelItem.
*
* The returned item must be unreffed eventually.
*
* Return value: a copy of @item
**/
KatzeXbelItem*
katze_xbel_item_copy (KatzeXbelItem* item)
{
g_return_val_if_fail (item, NULL);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
KatzeXbelItem* copy = katze_xbel_item_new (priv->kind);
if (katze_xbel_item_is_folder (item))
{
guint n = katze_xbel_folder_get_n_items (item);
guint i;
for (i = 0; i < n; i++)
{
KatzeXbelItem* _item = katze_xbel_folder_get_nth_item (item, i);
katze_xbel_folder_append_item (copy, katze_xbel_item_copy (_item));
}
}
if (priv->kind != KATZE_XBEL_ITEM_KIND_SEPARATOR)
{
katze_xbel_item_set_title (copy, priv->title);
katze_xbel_item_set_desc (copy, priv->desc);
}
if (priv->kind == KATZE_XBEL_ITEM_KIND_BOOKMARK)
katze_xbel_bookmark_set_href (copy, priv->href);
return copy;
}
GType
katze_xbel_item_get_type (void)
{
static GType type = 0;
if (!type)
type = g_pointer_type_register_static ("katze_xbel_item");
return type;
}
/**
* katze_xbel_folder_append_item:
* @folder: a folder
* @item: the item to append
*
* Append the given item to a folder.
*
* The item is actually moved and must not be contained in another folder.
*
**/
void
katze_xbel_folder_append_item (KatzeXbelItem* folder,
KatzeXbelItem* item)
{
g_return_if_fail (!katze_xbel_item_get_parent (item));
g_return_if_fail (katze_xbel_item_is_folder (folder));
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (folder);
priv->items = g_list_append (priv->items, item);
KATZE_XBEL_ITEM_GET_PRIVATE (item)->parent = folder;
}
/**
* katze_xbel_folder_prepend_item:
* @folder: a folder
* @item: the item to prepend
*
* Prepend the given item to a folder.
*
* The item is actually moved and must not be contained in another folder.
*
**/
void
katze_xbel_folder_prepend_item (KatzeXbelItem* folder,
KatzeXbelItem* item)
{
g_return_if_fail (!katze_xbel_item_get_parent (item));
g_return_if_fail (katze_xbel_item_is_folder (folder));
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (folder);
priv->items = g_list_prepend (priv->items, item);
KATZE_XBEL_ITEM_GET_PRIVATE (item)->parent = folder;
}
/**
* katze_xbel_folder_remove_item:
* @folder: a folder
* @item: the item to remove
*
* Remove the given @item from a @folder.
**/
void
katze_xbel_folder_remove_item (KatzeXbelItem* folder,
KatzeXbelItem* item)
{
g_return_if_fail (item);
g_return_if_fail (katze_xbel_item_get_parent(folder) != item);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (folder);
// Fortunately we know that items are unique
priv->items = g_list_remove (priv->items, item);
KATZE_XBEL_ITEM_GET_PRIVATE (item)->parent = NULL;
}
/**
* katze_xbel_folder_get_n_items:
* @folder: a folder
*
* Retrieve the number of items contained in the given @folder.
*
* Return value: number of items
**/
guint
katze_xbel_folder_get_n_items (KatzeXbelItem* folder)
{
g_return_val_if_fail (katze_xbel_item_is_folder (folder), 0);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (folder);
return g_list_length (priv->items);
}
/**
* katze_xbel_folder_get_nth_item:
* @folder: a folder
* @n: the index of an item
*
* Retrieve an item contained in the given @folder by its index.
*
* Return value: the item at the given index or %NULL
**/
KatzeXbelItem*
katze_xbel_folder_get_nth_item (KatzeXbelItem* folder,
guint n)
{
g_return_val_if_fail (katze_xbel_item_is_folder(folder), NULL);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (folder);
return (KatzeXbelItem*) g_list_nth_data (priv->items, n);
}
/**
* katze_xbel_folder_is_empty:
* @folder: A folder.
*
* Determines wether or not a folder contains no items. This is significantly
* faster than katze_xbel_folder_get_n_items for this particular purpose.
*
* Return value: Wether the given @folder is folded.
**/
gboolean
katze_xbel_folder_is_empty (KatzeXbelItem* folder)
{
return !katze_xbel_folder_get_nth_item (folder, 0);
}
/**
* katze_xbel_folder_get_folded:
* @folder: A folder.
*
* Determines wether or not a folder is folded. If a folder is not folded
* it should not be exposed in a user interface.
*
* New folders are folded by default.
*
* Return value: Wether the given @folder is folded.
**/
gboolean
katze_xbel_folder_get_folded (KatzeXbelItem* folder)
{
g_return_val_if_fail (katze_xbel_item_is_folder (folder), TRUE);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (folder);
return priv->folded;
}
/**
* katze_xbel_item_get_kind:
* @item: A item.
*
* Determines the kind of an item.
*
* Return value: The kind of the given @item.
**/
KatzeXbelItemKind
katze_xbel_item_get_kind (KatzeXbelItem* item)
{
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
return priv->kind;
}
/**
* katze_xbel_item_get_parent:
* @item: A valid item.
*
* Retrieves the parent folder of an item.
*
* Return value: The parent folder of the given @item or %NULL.
**/
KatzeXbelItem*
katze_xbel_item_get_parent (KatzeXbelItem* item)
{
g_return_val_if_fail (item, NULL);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
return priv->parent;
}
/**
* katze_xbel_item_get_title:
* @item: A valid item.
*
* Retrieves the title of an item.
*
* Return value: The title of the given @item or %NULL.
**/
G_CONST_RETURN gchar*
katze_xbel_item_get_title (KatzeXbelItem* item)
{
g_return_val_if_fail (!katze_xbel_item_is_separator (item), NULL);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
return priv->title;
}
/**
* katze_xbel_item_get_desc:
* @item: A valid item.
*
* Retrieves the description of an item.
*
* Return value: The description of the @item or %NULL.
**/
G_CONST_RETURN gchar*
katze_xbel_item_get_desc (KatzeXbelItem* item)
{
g_return_val_if_fail (!katze_xbel_item_is_separator (item), NULL);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
return priv->desc;
}
/**
* katze_xbel_bookmark_get_href:
* @bookmark: A bookmark.
*
* Retrieves the uri of a bookmark. The value is guaranteed to not be %NULL.
*
* Return value: The uri of the @bookmark.
**/
G_CONST_RETURN gchar*
katze_xbel_bookmark_get_href (KatzeXbelItem* bookmark)
{
g_return_val_if_fail (katze_xbel_item_is_bookmark (bookmark), NULL);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (bookmark);
return priv->href;
}
/**
* katze_xbel_item_is_bookmark:
* @item: A valid item.
*
* Determines wether or not an item is a bookmark.
*
* Return value: %TRUE if the @item is a bookmark.
**/
gboolean
katze_xbel_item_is_bookmark (KatzeXbelItem* item)
{
g_return_val_if_fail (item, FALSE);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
return priv->kind == KATZE_XBEL_ITEM_KIND_BOOKMARK;
}
/**
* katze_xbel_item_is_separator:
* @item: A valid item.
*
* Determines wether or not an item is a separator.
*
* Return value: %TRUE if the @item is a separator.
**/
gboolean katze_xbel_item_is_separator (KatzeXbelItem* item)
{
g_return_val_if_fail (item, FALSE);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
return priv->kind == KATZE_XBEL_ITEM_KIND_SEPARATOR;
}
/**
* katze_xbel_item_is_folder:
* @item: A valid item.
*
* Determines wether or not an item is a folder.
*
* Return value: %TRUE if the item is a folder.
**/
gboolean
katze_xbel_item_is_folder (KatzeXbelItem* item)
{
g_return_val_if_fail (item, FALSE);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
return priv->kind == KATZE_XBEL_ITEM_KIND_FOLDER;
}
/**
* katze_xbel_folder_set_folded:
* @folder: A folder.
* @folded: TRUE if the folder is folded.
*
* Sets the foldedness of the @folder.
**/
void
katze_xbel_folder_set_folded (KatzeXbelItem* folder,
gboolean folded)
{
g_return_if_fail (katze_xbel_item_is_folder (folder));
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (folder);
priv->folded = folded;
}
/**
* katze_xbel_item_set_title:
* @item: A valid item.
* @title: A string to use for the title.
*
* Sets the title of the @item.
**/
void
katze_xbel_item_set_title (KatzeXbelItem* item,
const gchar* title)
{
g_return_if_fail (!katze_xbel_item_is_separator (item));
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
katze_assign (priv->title, g_strdup (title));
}
/**
* katze_xbel_item_set_desc:
* @item: A valid item.
* @title: A string to use for the description.
*
* Sets the description of the @item.
**/
void
katze_xbel_item_set_desc (KatzeXbelItem* item,
const gchar* desc)
{
g_return_if_fail (!katze_xbel_item_is_separator (item));
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
katze_assign (priv->desc, g_strdup (desc));
}
/**
* katze_xbel_bookmark_set_href:
* @bookmark: A bookmark.
* @href: A string containing a valid uri.
*
* Sets the uri of the bookmark.
*
* The uri must not be %NULL.
*
* This uri is not currently validated in any way. This may change in the future.
**/
void
katze_xbel_bookmark_set_href (KatzeXbelItem* bookmark,
const gchar* href)
{
g_return_if_fail (katze_xbel_item_is_bookmark (bookmark));
g_return_if_fail (href);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (bookmark);
katze_assign (priv->href, g_strdup (href));
}
gboolean
katze_xbel_folder_from_data (KatzeXbelItem* folder,
const gchar* data,
GError** error)
{
g_return_val_if_fail (katze_xbel_folder_is_empty (folder), FALSE);
g_return_val_if_fail (data, FALSE);
xmlDocPtr doc;
if((doc = xmlParseMemory (data, strlen (data))) == NULL)
{
// No valid xml or broken encoding
*error = g_error_new (KATZE_XBEL_ERROR, KATZE_XBEL_ERROR_READ,
"Malformed document.");
return FALSE;
}
if (!katze_xbel_folder_from_xmlDocPtr (folder, doc))
{
// Parsing failed
xmlFreeDoc(doc);
*error = g_error_new (KATZE_XBEL_ERROR, KATZE_XBEL_ERROR_READ,
"Malformed document.");
return FALSE;
}
xmlFreeDoc(doc);
return TRUE;
}
/**
* katze_xbel_folder_from_file:
* @folder: An empty folder.
* @file: A relative path to a file.
* @error: return location for a GError or %NULL
*
* Tries to load @file.
*
* Return value: %TRUE on success or %FALSE when an error occured.
**/
gboolean
katze_xbel_folder_from_file (KatzeXbelItem* folder,
const gchar* file,
GError** error)
{
g_return_val_if_fail (katze_xbel_folder_is_empty (folder), FALSE);
g_return_val_if_fail (file, FALSE);
if (!g_file_test (file, G_FILE_TEST_EXISTS))
{
// File doesn't exist
*error = g_error_new (G_FILE_ERROR, G_FILE_ERROR_NOENT,
"File not found.");
return FALSE;
}
xmlDocPtr doc;
if ((doc = xmlParseFile (file)) == NULL)
{
// No valid xml or broken encoding
*error = g_error_new (KATZE_XBEL_ERROR, KATZE_XBEL_ERROR_READ,
"Malformed document.");
return FALSE;
}
if (!katze_xbel_folder_from_xmlDocPtr (folder, doc))
{
// Parsing failed
xmlFreeDoc (doc);
*error = g_error_new (KATZE_XBEL_ERROR, KATZE_XBEL_ERROR_READ,
"Malformed document.");
return FALSE;
}
xmlFreeDoc (doc);
return TRUE;
}
/**
* katze_xbel_folder_from_data_dirs:
* @folder: An empty folder.
* @file: A relative path to a file.
* @full_path: return location for the full path of the file or %NULL
* @error: return location for a GError or %NULL
*
* Tries to load @file from the user data dir or any of the system data dirs.
*
* Return value: %TRUE on success or %FALSE when an error occured.
**/
gboolean
katze_xbel_folder_from_data_dirs (KatzeXbelItem* folder,
const gchar* file,
gchar** full_path,
GError** error)
{
g_return_val_if_fail (katze_xbel_folder_is_empty (folder), FALSE);
g_return_val_if_fail (file, FALSE);
// FIXME: Essentially unimplemented
*error = g_error_new (KATZE_XBEL_ERROR, KATZE_XBEL_ERROR_READ,
"Malformed document.");
return FALSE;
}
static gchar*
katze_xbel_xml_element (const gchar* name,
const gchar* value)
{
if (!value)
return g_strdup ("");
gchar* valueEscaped = g_markup_escape_text (value, -1);
gchar* markup = g_strdup_printf ("<%s>%s</%s>\n",
name, valueEscaped, name);
g_free (valueEscaped);
return markup;
}
static gchar*
katze_xbel_item_to_data (KatzeXbelItem* item)
{
g_return_val_if_fail (item, NULL);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (item);
gchar* markup = NULL;
switch (priv->kind)
{
case KATZE_XBEL_ITEM_KIND_FOLDER:
{
GString* _markup = g_string_new (NULL);
guint n = katze_xbel_folder_get_n_items (item);
guint i;
for (i = 0; i < n; i++)
{
KatzeXbelItem* _item = katze_xbel_folder_get_nth_item (item, i);
gchar* item_markup = katze_xbel_item_to_data (_item);
g_string_append (_markup, item_markup);
g_free (item_markup);
}
gchar* folded = priv->folded ? NULL : g_strdup_printf (" folded=\"no\"");
gchar* title = katze_xbel_xml_element ("title", priv->title);
gchar* desc = katze_xbel_xml_element ("desc", priv->desc);
markup = g_strdup_printf ("<folder%s>\n%s%s%s</folder>\n",
folded ? folded : "",
title, desc,
g_string_free (_markup, FALSE));
g_free (folded);
g_free (title);
g_free (desc);
break;
}
case KATZE_XBEL_ITEM_KIND_BOOKMARK:
{
gchar* href_escaped = g_markup_escape_text (priv->href, -1);
gchar* href = g_strdup_printf (" href=\"%s\"", href_escaped);
g_free (href_escaped);
gchar* title = katze_xbel_xml_element ("title", priv->title);
gchar* desc = katze_xbel_xml_element ("desc", priv->desc);
markup = g_strdup_printf ("<bookmark%s>\n%s%s%s</bookmark>\n",
href,
title, desc,
"");
g_free (href);
g_free (title);
g_free (desc);
break;
}
case KATZE_XBEL_ITEM_KIND_SEPARATOR:
markup = g_strdup ("<separator/>\n");
break;
default:
g_warning ("XBEL: Unknown item kind");
}
return markup;
}
/**
* katze_xbel_folder_to_data:
* @folder: A folder.
* @length: return location for the length of the created string or %NULL
* @error: return location for a GError or %NULL
*
* Retrieve the contents of @folder as a string.
*
* Return value: %TRUE on success or %FALSE when an error occured.
**/
gchar*
katze_xbel_folder_to_data (KatzeXbelItem* folder,
gsize* length,
GError** error)
{
g_return_val_if_fail (katze_xbel_item_is_folder (folder), FALSE);
KatzeXbelItemPrivate* priv = KATZE_XBEL_ITEM_GET_PRIVATE (folder);
GString* inner_markup = g_string_new (NULL);
guint n = katze_xbel_folder_get_n_items (folder);
guint i;
for (i = 0; i < n; i++)
{
KatzeXbelItem* item = katze_xbel_folder_get_nth_item (folder, i);
gchar* sItem = katze_xbel_item_to_data (item);
g_string_append (inner_markup, sItem);
g_free (sItem);
}
gchar* title = katze_xbel_xml_element ("title", priv->title);
gchar* desc = katze_xbel_xml_element ("desc", priv->desc);
gchar* outer_markup;
outer_markup = g_strdup_printf (
"%s%s<xbel version=\"1.0\">\n%s%s%s</xbel>\n",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD "
"XML Bookmark Exchange Language 1.0//EN//XML\" "
"\"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">\n",
title,
desc,
g_string_free (inner_markup, FALSE));
g_free (title);
g_free (desc);
if (length)
*length = strlen (outer_markup);
return outer_markup;
}
/**
* katze_xbel_folder_to_file:
* @folder: A folder.
* @file: The destination filename.
* @error: return location for a GError or %NULL
*
* Write the contents of @folder to the specified file, creating it if necessary.
*
* Return value: %TRUE on success or %FALSE when an error occured.
**/
gboolean
katze_xbel_folder_to_file (KatzeXbelItem* folder,
const gchar* file,
GError** error)
{
g_return_val_if_fail (file, FALSE);
gchar* data;
if (!(data = katze_xbel_folder_to_data (folder, NULL, error)))
return FALSE;
FILE* fp;
if(!(fp = fopen (file, "w")))
{
*error = g_error_new (G_FILE_ERROR, G_FILE_ERROR_ACCES,
"Writing failed.");
return FALSE;
}
fputs (data, fp);
fclose (fp);
g_free (data);
return TRUE;
}

176
katze/katze-xbel.h Normal file
View File

@ -0,0 +1,176 @@
/*
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
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.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __KATZE_XBEL_H__
#define __KATZE_XBEL_H__ 1
#include <glib-object.h>
G_BEGIN_DECLS
#define KATZE_TYPE_XBEL_ITEM \
(katze_xbel_item_get_type ())
typedef struct _KatzeXbelItem KatzeXbelItem;
typedef struct _KatzeXbelItemPrivate KatzeXbelItemPrivate;
struct _KatzeXbelItem
{
KatzeXbelItemPrivate* priv;
/* Padding for future expansion */
void (*_katze_reserved1) (void);
void (*_katze_reserved2) (void);
void (*_katze_reserved3) (void);
void (*_katze_reserved4) (void);
};
#define KATZE_XBEL_ERROR g_quark_from_string("KATZE_XBEL_ERROR")
typedef enum
{
KATZE_XBEL_ERROR_INVALID_URI, /* Malformed uri */
KATZE_XBEL_ERROR_INVALID_VALUE, /* Requested field not found */
KATZE_XBEL_ERROR_URI_NOT_FOUND, /* Requested uri not found */
KATZE_XBEL_ERROR_READ, /* Malformed document */
KATZE_XBEL_ERROR_UNKNOWN_ENCODING, /* Parsed text was in an unknown encoding */
KATZE_XBEL_ERROR_WRITE, /* Writing failed. */
} KatzeXbelError;
typedef enum
{
KATZE_XBEL_ITEM_KIND_FOLDER,
KATZE_XBEL_ITEM_KIND_BOOKMARK,
KATZE_XBEL_ITEM_KIND_SEPARATOR
} KatzeXbelItemKind;
GType
katze_xbel_item_get_type (void) G_GNUC_CONST;
KatzeXbelItem*
katze_xbel_bookmark_new (void);
KatzeXbelItem*
katze_xbel_separator_new (void);
KatzeXbelItem*
katze_xbel_folder_new (void);
void
katze_xbel_item_ref (KatzeXbelItem* item);
void
katze_xbel_item_unref (KatzeXbelItem* item);
KatzeXbelItem*
katze_xbel_item_copy (KatzeXbelItem* item);
void
katze_xbel_folder_append_item (KatzeXbelItem* folder,
KatzeXbelItem* item);
void
katze_xbel_folder_prepend_item (KatzeXbelItem* folder,
KatzeXbelItem* item);
void
katze_xbel_folder_remove_item (KatzeXbelItem* folder,
KatzeXbelItem* item);
guint
katze_xbel_folder_get_n_items (KatzeXbelItem* folder);
KatzeXbelItem*
katze_xbel_folder_get_nth_item (KatzeXbelItem* folder,
guint n);
gboolean
katze_xbel_folder_is_empty (KatzeXbelItem* folder);
gboolean
katze_xbel_folder_get_folded (KatzeXbelItem* folder);
KatzeXbelItemKind
katze_xbel_item_get_kind (KatzeXbelItem* item);
KatzeXbelItem*
katze_xbel_item_get_parent (KatzeXbelItem* item);
G_CONST_RETURN gchar*
katze_xbel_item_get_title (KatzeXbelItem* item);
G_CONST_RETURN gchar*
katze_xbel_item_get_desc (KatzeXbelItem* item);
G_CONST_RETURN gchar*
katze_xbel_bookmark_get_href (KatzeXbelItem* bookmark);
/*time_t
katze_xbel_bookmark_get_added (KatzeXbelItem* bookmark);
time_t
katze_xbel_bookmark_get_modified (KatzeXbelItem* bookmark);
time_t
katze_xbel_bookmark_get_visited (KatzeXbelItem* bookmark);*/
gboolean
katze_xbel_item_is_bookmark (KatzeXbelItem* bookmark);
gboolean
katze_xbel_item_is_separator (KatzeXbelItem* bookmark);
gboolean
katze_xbel_item_is_folder (KatzeXbelItem* bookmark);
void
katze_xbel_folder_set_folded (KatzeXbelItem* folder,
gboolean folded);
void
katze_xbel_item_set_title (KatzeXbelItem* item,
const gchar* title);
void
katze_xbel_item_set_desc (KatzeXbelItem* item,
const gchar* desc);
void
katze_xbel_bookmark_set_href (KatzeXbelItem* bookmark,
const gchar* href);
gboolean
katze_xbel_folder_from_data (KatzeXbelItem* folder,
const gchar* data,
GError** error);
gboolean
katze_xbel_folder_from_file (KatzeXbelItem* folder,
const gchar* file,
GError** error);
gboolean
katze_xbel_folder_from_data_dirs (KatzeXbelItem* folder,
const gchar* file,
gchar** full_path,
GError** error);
gchar*
katze_xbel_folder_to_data (KatzeXbelItem* folder,
gsize* length,
GError** error);
gboolean
katze_xbel_folder_to_file (KatzeXbelItem* folder,
const gchar* file,
GError** error);
#endif /* !__KATZE_XBEL_H__ */

View File

@ -14,5 +14,6 @@
#include "katze-throbber.h"
#include "katze-utils.h"
#include "katze-xbel.h"
#endif /* __KATZE_THROBBER_H__ */
#endif /* __KATZE_H__ */

View File

@ -1,14 +1,12 @@
INCLUDES = \
$(GTK_CFLAGS) \
$(WEBKIT_CFLAGS) \
$(LIBXML_CFLAGS) \
$(LIBSEXY_CFLAGS) \
-I../katze
LDADD = \
$(GTK_LIBS) \
$(WEBKIT_LIBS) \
$(LIBXML_LIBS) \
$(LIBSEXY_LIBS) \
../katze/libkatze.la
@ -25,7 +23,6 @@ midori_SOURCES = \
sokoke.c sokoke.h \
conf.c conf.h \
search.c search.h \
xbel.c xbel.h \
global.h \
ui.h \
debug.h

View File

@ -17,7 +17,6 @@
#include "ui.h"
#include "webView.h"
#include "webSearch.h"
#include "xbel.h"
#include "../katze/katze.h"
#include <gdk/gdkkeysyms.h>
@ -379,20 +378,20 @@ void on_action_webSearch_activate(GtkAction* action, CBrowser* browser)
void on_menu_tabsClosed_activate(GtkWidget* widget, CBrowser* browser)
{
GtkWidget* menu = gtk_menu_new();
guint n = xbel_folder_get_n_items(tabtrash);
guint n = katze_xbel_folder_get_n_items(tabtrash);
GtkWidget* menuitem;
guint i;
for(i = 0; i < n; i++)
{
XbelItem* item = xbel_folder_get_nth_item(tabtrash, i);
const gchar* title = xbel_item_get_title(item);
const gchar* uri = xbel_bookmark_get_href(item);
KatzeXbelItem* item = katze_xbel_folder_get_nth_item(tabtrash, i);
const gchar* title = katze_xbel_item_get_title(item);
const gchar* uri = katze_xbel_bookmark_get_href(item);
menuitem = gtk_image_menu_item_new_with_label(title ? title : uri);
// FIXME: Get the real icon
GtkWidget* icon = gtk_image_new_from_stock(GTK_STOCK_FILE, GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), icon);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
g_object_set_data(G_OBJECT(menuitem), "XbelItem", item);
g_object_set_data(G_OBJECT(menuitem), "KatzeXbelItem", item);
g_signal_connect(menuitem, "activate", G_CALLBACK(on_menu_tabsClosed_item_activate), browser);
gtk_widget_show(menuitem);
}
@ -411,30 +410,30 @@ void on_menu_tabsClosed_activate(GtkWidget* widget, CBrowser* browser)
void on_menu_tabsClosed_item_activate(GtkWidget* menuitem, CBrowser* browser)
{
// Create a new webView with an uri which has been closed before
XbelItem* item = g_object_get_data(G_OBJECT(menuitem), "XbelItem");
const gchar* uri = xbel_bookmark_get_href(item);
KatzeXbelItem* item = g_object_get_data(G_OBJECT(menuitem), "KatzeXbelItem");
const gchar* uri = katze_xbel_bookmark_get_href(item);
CBrowser* curBrowser = browser_new(browser);
webView_open(curBrowser->webView, uri);
xbel_item_unref(item);
katze_xbel_item_unref(item);
update_browser_actions(curBrowser);
}
void on_action_tabsClosed_undo_activate(GtkAction* action, CBrowser* browser)
{
// Open the most recent tabtrash item
XbelItem* item = xbel_folder_get_nth_item(tabtrash, 0);
const gchar* uri = xbel_bookmark_get_href(item);
KatzeXbelItem* item = katze_xbel_folder_get_nth_item(tabtrash, 0);
const gchar* uri = katze_xbel_bookmark_get_href(item);
CBrowser* curBrowser = browser_new(browser);
webView_open(curBrowser->webView, uri);
xbel_item_unref(item);
katze_xbel_item_unref(item);
update_browser_actions(curBrowser);
}
void on_action_tabsClosed_clear_activate(GtkAction* action, CBrowser* browser)
{
// Clear the closed tabs list
xbel_item_unref(tabtrash);
tabtrash = xbel_folder_new();
katze_xbel_item_unref(tabtrash);
tabtrash = katze_xbel_folder_new();
update_browser_actions(browser);
}
@ -466,7 +465,7 @@ void on_action_link_copy_activate(GtkAction* action, CBrowser* browser)
gtk_clipboard_set_text(clipboard, browser->elementUri, -1);
}
static void browser_editBookmark_dialog_new(XbelItem* bookmark, CBrowser* browser)
static void browser_editBookmark_dialog_new(KatzeXbelItem* bookmark, CBrowser* browser)
{
gboolean newBookmark = !bookmark;
GtkWidget* dialog = gtk_dialog_new_with_buttons(
@ -483,7 +482,7 @@ static void browser_editBookmark_dialog_new(XbelItem* bookmark, CBrowser* browse
GtkSizeGroup* sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
if(newBookmark)
bookmark = xbel_bookmark_new();
bookmark = katze_xbel_bookmark_new();
GtkWidget* hbox = gtk_hbox_new(FALSE, 8);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
@ -494,7 +493,7 @@ static void browser_editBookmark_dialog_new(XbelItem* bookmark, CBrowser* browse
gtk_entry_set_activates_default(GTK_ENTRY(entry_title), TRUE);
if(!newBookmark)
{
const gchar* title = xbel_item_get_title(bookmark);
const gchar* title = katze_xbel_item_get_title(bookmark);
gtk_entry_set_text(GTK_ENTRY(entry_title), title ? title : "");
}
gtk_box_pack_start(GTK_BOX(hbox), entry_title, TRUE, TRUE, 0);
@ -510,7 +509,7 @@ static void browser_editBookmark_dialog_new(XbelItem* bookmark, CBrowser* browse
gtk_entry_set_activates_default(GTK_ENTRY(entry_desc), TRUE);
if(!newBookmark)
{
const gchar* desc = xbel_item_get_desc(bookmark);
const gchar* desc = katze_xbel_item_get_desc(bookmark);
gtk_entry_set_text(GTK_ENTRY(entry_desc), desc ? desc : "");
}
gtk_box_pack_start(GTK_BOX(hbox), entry_desc, TRUE, TRUE, 0);
@ -518,7 +517,7 @@ static void browser_editBookmark_dialog_new(XbelItem* bookmark, CBrowser* browse
gtk_widget_show_all(hbox);
GtkWidget* entry_uri = NULL;
if(xbel_item_is_bookmark(bookmark))
if(katze_xbel_item_is_bookmark(bookmark))
{
hbox = gtk_hbox_new(FALSE, 8);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
@ -528,7 +527,7 @@ static void browser_editBookmark_dialog_new(XbelItem* bookmark, CBrowser* browse
entry_uri = gtk_entry_new();
gtk_entry_set_activates_default(GTK_ENTRY(entry_uri), TRUE);
if(!newBookmark)
gtk_entry_set_text(GTK_ENTRY(entry_uri), xbel_bookmark_get_href(bookmark));
gtk_entry_set_text(GTK_ENTRY(entry_uri), katze_xbel_bookmark_get_href(bookmark));
gtk_box_pack_start(GTK_BOX(hbox), entry_uri, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
gtk_widget_show_all(hbox);
@ -537,14 +536,14 @@ static void browser_editBookmark_dialog_new(XbelItem* bookmark, CBrowser* browse
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
{
xbel_item_set_title(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_title)));
xbel_item_set_desc(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_desc)));
if(xbel_item_is_bookmark(bookmark))
xbel_bookmark_set_href(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_uri)));
katze_xbel_item_set_title(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_title)));
katze_xbel_item_set_desc(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_desc)));
if(katze_xbel_item_is_bookmark(bookmark))
katze_xbel_bookmark_set_href(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_uri)));
// FIXME: We want to choose a folder
if(newBookmark)
xbel_folder_append_item(bookmarks, bookmark);
katze_xbel_folder_append_item(bookmarks, bookmark);
}
gtk_widget_destroy(dialog);
}
@ -556,18 +555,18 @@ static void on_panel_bookmarks_row_activated(GtkTreeView* treeview
GtkTreeIter iter;
if(gtk_tree_model_get_iter(model, &iter, path))
{
XbelItem* item;
KatzeXbelItem* item;
gtk_tree_model_get(model, &iter, 0, &item, -1);
if(xbel_item_is_bookmark(item))
webView_open(get_nth_webView(-1, browser), xbel_bookmark_get_href(item));
if(katze_xbel_item_is_bookmark(item))
webView_open(get_nth_webView(-1, browser), katze_xbel_bookmark_get_href(item));
}
}
static void panel_bookmarks_popup(GtkWidget* widget, GdkEventButton* event
, XbelItem* item, CBrowser* browser)
, KatzeXbelItem* item, CBrowser* browser)
{
gboolean isBookmark = xbel_item_is_bookmark(item);
gboolean isSeparator = xbel_item_is_separator(item);
gboolean isBookmark = katze_xbel_item_is_bookmark(item);
gboolean isSeparator = katze_xbel_item_is_separator(item);
action_set_sensitive("BookmarkOpen", isBookmark, browser);
action_set_sensitive("BookmarkOpenTab", isBookmark, browser);
@ -590,12 +589,12 @@ static gboolean on_panel_bookmarks_button_release(GtkWidget* widget
GtkTreeModel* model;
GtkTreeIter iter;
gtk_tree_selection_get_selected(selection, &model, &iter);
XbelItem* item;
KatzeXbelItem* item;
gtk_tree_model_get(model, &iter, 0, &item, -1);
if(event->button == 2 && xbel_item_is_bookmark(item))
if(event->button == 2 && katze_xbel_item_is_bookmark(item))
{
CBrowser* newBrowser = browser_new(browser);
const gchar* uri = xbel_bookmark_get_href(item);
const gchar* uri = katze_xbel_bookmark_get_href(item);
webView_open(newBrowser->webView, uri);
}
else
@ -613,7 +612,7 @@ void on_panel_bookmarks_popup(GtkWidget* widget, CBrowser* browser)
GtkTreeModel* model;
GtkTreeIter iter;
gtk_tree_selection_get_selected(selection, &model, &iter);
XbelItem* item;
KatzeXbelItem* item;
gtk_tree_model_get(model, &iter, 0, &item, -1);
panel_bookmarks_popup(widget, NULL, item, browser);
}
@ -628,10 +627,10 @@ void on_action_bookmarkOpen_activate(GtkAction* action, CBrowser* browser)
GtkTreeModel* model;
GtkTreeIter iter;
gtk_tree_selection_get_selected(selection, &model, &iter);
XbelItem* item;
KatzeXbelItem* item;
gtk_tree_model_get(model, &iter, 0, &item, -1);
if(xbel_item_is_bookmark(item))
webView_open(get_nth_webView(-1, browser), xbel_bookmark_get_href(item));
if(katze_xbel_item_is_bookmark(item))
webView_open(get_nth_webView(-1, browser), katze_xbel_bookmark_get_href(item));
}
}
@ -644,12 +643,12 @@ void on_action_bookmarkOpenTab_activate(GtkAction* action, CBrowser* browser)
GtkTreeModel* model;
GtkTreeIter iter;
gtk_tree_selection_get_selected(selection, &model, &iter);
XbelItem* item;
KatzeXbelItem* item;
gtk_tree_model_get(model, &iter, 0, &item, -1);
if(xbel_item_is_bookmark(item))
if(katze_xbel_item_is_bookmark(item))
{
CBrowser* newBrowser = browser_new(browser);
const gchar* uri = xbel_bookmark_get_href(item);
const gchar* uri = katze_xbel_bookmark_get_href(item);
webView_open(newBrowser->webView, uri);
}
}
@ -664,12 +663,12 @@ void on_action_bookmarkOpenWindow_activate(GtkAction* action, CBrowser* browser)
GtkTreeModel* model;
GtkTreeIter iter;
gtk_tree_selection_get_selected(selection, &model, &iter);
XbelItem* item;
KatzeXbelItem* item;
gtk_tree_model_get(model, &iter, 0, &item, -1);
if(xbel_item_is_bookmark(item))
if(katze_xbel_item_is_bookmark(item))
{
CBrowser* newBrowser = browser_new(NULL);
const gchar* uri = xbel_bookmark_get_href(item);
const gchar* uri = katze_xbel_bookmark_get_href(item);
webView_open(newBrowser->webView, uri);
}
}
@ -684,9 +683,9 @@ void on_action_bookmarkEdit_activate(GtkAction* action, CBrowser* browser)
GtkTreeModel* model;
GtkTreeIter iter;
gtk_tree_selection_get_selected(selection, &model, &iter);
XbelItem* item;
KatzeXbelItem* item;
gtk_tree_model_get(model, &iter, 0, &item, -1);
if(!xbel_item_is_separator(item))
if(!katze_xbel_item_is_separator(item))
browser_editBookmark_dialog_new(item, browser);
}
}
@ -700,26 +699,26 @@ void on_action_bookmarkDelete_activate(GtkAction* action, CBrowser* browser)
GtkTreeModel* model;
GtkTreeIter iter;
gtk_tree_selection_get_selected(selection, &model, &iter);
XbelItem* item;
KatzeXbelItem* item;
gtk_tree_model_get(model, &iter, 0, &item, -1);
XbelItem* parent = xbel_item_get_parent(item);
xbel_folder_remove_item(parent, item);
xbel_item_unref(item);
KatzeXbelItem* parent = katze_xbel_item_get_parent(item);
katze_xbel_folder_remove_item(parent, item);
katze_xbel_item_unref(item);
}
}
static void tree_store_insert_folder(GtkTreeStore* treestore, GtkTreeIter* parent
, XbelItem* folder)
, KatzeXbelItem* folder)
{
guint n = xbel_folder_get_n_items(folder);
guint n = katze_xbel_folder_get_n_items(folder);
guint i;
for(i = 0; i < n; i++)
{
XbelItem* item = xbel_folder_get_nth_item(folder, i);
KatzeXbelItem* item = katze_xbel_folder_get_nth_item(folder, i);
GtkTreeIter iter;
gtk_tree_store_insert_with_values(treestore, &iter, parent, n, 0, item, -1);
xbel_item_ref(item);
if(xbel_item_is_folder(item))
katze_xbel_item_ref(item);
if(katze_xbel_item_is_folder(item))
tree_store_insert_folder(treestore, &iter, item);
}
}
@ -728,22 +727,22 @@ static void on_bookmarks_item_render_icon(GtkTreeViewColumn* column
, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter
, GtkWidget* treeview)
{
XbelItem* item;
KatzeXbelItem* item;
gtk_tree_model_get(model, iter, 0, &item, -1);
if(!xbel_item_get_parent(item))
if(!katze_xbel_item_get_parent(item))
{
gtk_tree_store_remove(GTK_TREE_STORE(model), iter);
xbel_item_unref(item);
katze_xbel_item_unref(item);
return;
}
// TODO: Would it be better to not do this on every redraw?
GdkPixbuf* pixbuf = NULL;
if(xbel_item_is_bookmark(item))
if(katze_xbel_item_is_bookmark(item))
pixbuf = gtk_widget_render_icon(treeview, STOCK_BOOKMARK
, GTK_ICON_SIZE_MENU, NULL);
else if(xbel_item_is_folder(item))
else if(katze_xbel_item_is_folder(item))
pixbuf = gtk_widget_render_icon(treeview, GTK_STOCK_DIRECTORY
, GTK_ICON_SIZE_MENU, NULL);
g_object_set(renderer, "pixbuf", pixbuf, NULL);
@ -755,31 +754,31 @@ static void on_bookmarks_item_render_text(GtkTreeViewColumn* column
, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter
, GtkWidget* treeview)
{
XbelItem* item;
KatzeXbelItem* item;
gtk_tree_model_get(model, iter, 0, &item, -1);
if(!xbel_item_get_parent(item))
if(!katze_xbel_item_get_parent(item))
{
gtk_tree_store_remove(GTK_TREE_STORE(model), iter);
xbel_item_unref(item);
katze_xbel_item_unref(item);
return;
}
if(xbel_item_is_separator(item))
if(katze_xbel_item_is_separator(item))
g_object_set(renderer
, "markup", "<i>Separator</i>", NULL);
else
g_object_set(renderer
, "markup", NULL, "text", xbel_item_get_title(item), NULL);
, "markup", NULL, "text", katze_xbel_item_get_title(item), NULL);
}
static void create_bookmark_menu(XbelItem*, GtkWidget*, CBrowser*);
static void create_bookmark_menu(KatzeXbelItem*, GtkWidget*, CBrowser*);
static void on_bookmark_menu_folder_activate(GtkWidget* menuitem, CBrowser* browser)
{
GtkWidget* menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem));
gtk_container_foreach(GTK_CONTAINER(menu), (GtkCallback)gtk_widget_destroy, NULL);//...
XbelItem* folder = (XbelItem*)g_object_get_data(G_OBJECT(menuitem), "XbelItem");
KatzeXbelItem* folder = (KatzeXbelItem*)g_object_get_data(G_OBJECT(menuitem), "KatzeXbelItem");
create_bookmark_menu(folder, menu, browser);
// Remove all menuitems when the menu is hidden.
// FIXME: We really *want* the line below, but it won't work like that
@ -790,7 +789,7 @@ static void on_bookmark_menu_folder_activate(GtkWidget* menuitem, CBrowser* brow
static void on_bookmark_toolbar_folder_activate(GtkToolItem* toolitem, CBrowser* browser)
{
GtkWidget* menu = gtk_menu_new();
XbelItem* folder = (XbelItem*)g_object_get_data(G_OBJECT(toolitem), "XbelItem");
KatzeXbelItem* folder = (KatzeXbelItem*)g_object_get_data(G_OBJECT(toolitem), "KatzeXbelItem");
create_bookmark_menu(folder, menu, browser);
// Remove all menuitems when the menu is hidden.
// FIXME: We really *should* run the line below, but it won't work like that
@ -800,24 +799,24 @@ static void on_bookmark_toolbar_folder_activate(GtkToolItem* toolitem, CBrowser*
void on_menu_bookmarks_item_activate(GtkWidget* widget, CBrowser* browser)
{
XbelItem* item = (XbelItem*)g_object_get_data(G_OBJECT(widget), "XbelItem");
webView_open(get_nth_webView(-1, browser), xbel_bookmark_get_href(item));
KatzeXbelItem* item = (KatzeXbelItem*)g_object_get_data(G_OBJECT(widget), "KatzeXbelItem");
webView_open(get_nth_webView(-1, browser), katze_xbel_bookmark_get_href(item));
}
static void create_bookmark_menu(XbelItem* folder, GtkWidget* menu, CBrowser* browser)
static void create_bookmark_menu(KatzeXbelItem* folder, GtkWidget* menu, CBrowser* browser)
{
guint n = xbel_folder_get_n_items(folder);
guint n = katze_xbel_folder_get_n_items(folder);
guint i;
for(i = 0; i < n; i++)
{
XbelItem* item = xbel_folder_get_nth_item(folder, i);
const gchar* title = xbel_item_is_separator(item) ? "" : xbel_item_get_title(item);
//const gchar* desc = xbel_item_is_separator(item) ? "" : xbel_item_get_desc(item);
KatzeXbelItem* item = katze_xbel_folder_get_nth_item(folder, i);
const gchar* title = katze_xbel_item_is_separator(item) ? "" : katze_xbel_item_get_title(item);
//const gchar* desc = katze_xbel_item_is_separator(item) ? "" : katze_xbel_item_get_desc(item);
GtkWidget* menuitem = NULL;
switch(xbel_item_get_kind(item))
switch(katze_xbel_item_get_kind(item))
{
case XBEL_ITEM_FOLDER:
// FIXME: what about xbel_folder_is_folded?
case KATZE_XBEL_ITEM_KIND_FOLDER:
// FIXME: what about katze_xbel_folder_is_folded?
menuitem = gtk_image_menu_item_new_with_label(title);
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem)
, gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU));
@ -825,14 +824,14 @@ static void create_bookmark_menu(XbelItem* folder, GtkWidget* menu, CBrowser* br
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), _menu);
g_signal_connect(menuitem, "activate"
, G_CALLBACK(on_bookmark_menu_folder_activate), browser);
g_object_set_data(G_OBJECT(menuitem), "XbelItem", item);
g_object_set_data(G_OBJECT(menuitem), "KatzeXbelItem", item);
break;
case XBEL_ITEM_BOOKMARK:
case KATZE_XBEL_ITEM_KIND_BOOKMARK:
menuitem = menu_item_new(title, STOCK_BOOKMARK
, G_CALLBACK(on_menu_bookmarks_item_activate), TRUE, browser);
g_object_set_data(G_OBJECT(menuitem), "XbelItem", item);
g_object_set_data(G_OBJECT(menuitem), "KatzeXbelItem", item);
break;
case XBEL_ITEM_SEPARATOR:
case KATZE_XBEL_ITEM_KIND_SEPARATOR:
menuitem = gtk_separator_menu_item_new();
break;
default:
@ -936,7 +935,7 @@ void on_location_changed(GtkWidget* widget, CBrowser* browser)
{
// Preserve changes to the uri
/*const gchar* newUri = gtk_entry_get_text(GTK_ENTRY(widget));
xbel_bookmark_set_href(browser->sessionItem, newUri);*/
katze_xbel_bookmark_set_href(browser->sessionItem, newUri);*/
// FIXME: If we want this feature, this is the wrong approach
}
@ -1037,9 +1036,9 @@ void on_notebook_switch_page(GtkWidget* widget, GtkNotebookPage* page
{
GtkWidget* webView = get_nth_webView(page_num, browser);
browser = get_browser_from_webView(webView);
const gchar* uri = xbel_bookmark_get_href(browser->sessionItem);
const gchar* uri = katze_xbel_bookmark_get_href(browser->sessionItem);
gtk_entry_set_text(GTK_ENTRY(browser->location), uri);
const gchar* title = xbel_item_get_title(browser->sessionItem);
const gchar* title = katze_xbel_item_get_title(browser->sessionItem);
const gchar* effectiveTitle = title ? title : uri;
gchar* windowTitle = g_strconcat(effectiveTitle, " - ", PACKAGE_NAME, NULL);
gtk_window_set_title(GTK_WINDOW(browser->window), windowTitle);
@ -1098,9 +1097,9 @@ CBrowser* browser_new(CBrowser* oldBrowser)
{
CBrowser* browser = g_new0(CBrowser, 1);
browsers = g_list_prepend(browsers, browser);
browser->sessionItem = xbel_bookmark_new();
xbel_item_set_title(browser->sessionItem, "about:blank");
xbel_folder_append_item(session, browser->sessionItem);
browser->sessionItem = katze_xbel_bookmark_new();
katze_xbel_item_set_title(browser->sessionItem, "about:blank");
katze_xbel_folder_append_item(session, browser->sessionItem);
GtkWidget* scrolled;
@ -1289,26 +1288,26 @@ CBrowser* browser_new(CBrowser* oldBrowser)
gtk_toolbar_set_icon_size(GTK_TOOLBAR(browser->bookmarkbar), GTK_ICON_SIZE_MENU);
gtk_toolbar_set_style(GTK_TOOLBAR(browser->bookmarkbar), GTK_TOOLBAR_BOTH_HORIZ);
create_bookmark_menu(bookmarks, browser->menu_bookmarks, browser);
for(i = 0; i < xbel_folder_get_n_items(bookmarks); i++)
for(i = 0; i < katze_xbel_folder_get_n_items(bookmarks); i++)
{
XbelItem* item = xbel_folder_get_nth_item(bookmarks, i);
const gchar* title = xbel_item_is_separator(item)
? "" : xbel_item_get_title(item);
const gchar* desc = xbel_item_is_separator(item)
? "" : xbel_item_get_desc(item);
switch(xbel_item_get_kind(item))
KatzeXbelItem* item = katze_xbel_folder_get_nth_item(bookmarks, i);
const gchar* title = katze_xbel_item_is_separator(item)
? "" : katze_xbel_item_get_title(item);
const gchar* desc = katze_xbel_item_is_separator(item)
? "" : katze_xbel_item_get_desc(item);
switch(katze_xbel_item_get_kind(item))
{
case XBEL_ITEM_FOLDER:
case KATZE_XBEL_ITEM_KIND_FOLDER:
toolitem = tool_button_new(title, GTK_STOCK_DIRECTORY, TRUE, TRUE
, G_CALLBACK(on_bookmark_toolbar_folder_activate), desc, browser);
g_object_set_data(G_OBJECT(toolitem), "XbelItem", item);
g_object_set_data(G_OBJECT(toolitem), "KatzeXbelItem", item);
break;
case XBEL_ITEM_BOOKMARK:
case KATZE_XBEL_ITEM_KIND_BOOKMARK:
toolitem = tool_button_new(title, STOCK_BOOKMARK, TRUE, TRUE
, G_CALLBACK(on_menu_bookmarks_item_activate), desc, browser);
g_object_set_data(G_OBJECT(toolitem), "XbelItem", item);
g_object_set_data(G_OBJECT(toolitem), "KatzeXbelItem", item);
break;
case XBEL_ITEM_SEPARATOR:
case KATZE_XBEL_ITEM_KIND_SEPARATOR:
toolitem = gtk_separator_tool_item_new();
break;
default:
@ -1381,7 +1380,7 @@ CBrowser* browser_new(CBrowser* oldBrowser)
// Bookmarks
GtkTreeViewColumn* column;
GtkCellRenderer* renderer_text; GtkCellRenderer* renderer_pixbuf;
GtkTreeStore* treestore = gtk_tree_store_new(1, G_TYPE_XBEL_ITEM);
GtkTreeStore* treestore = gtk_tree_store_new(1, KATZE_TYPE_XBEL_ITEM);
GtkWidget* treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(treestore));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
column = gtk_tree_view_column_new();
@ -1566,7 +1565,7 @@ CBrowser* browser_new(CBrowser* oldBrowser)
katze_throbber_set_static_stock_id(KATZE_THROBBER(browser->webView_icon)
, GTK_STOCK_FILE);
gtk_box_pack_start(GTK_BOX(hbox), browser->webView_icon, FALSE, FALSE, 0);
browser->webView_name = gtk_label_new(xbel_item_get_title(browser->sessionItem));
browser->webView_name = gtk_label_new(katze_xbel_item_get_title(browser->sessionItem));
gtk_misc_set_alignment(GTK_MISC(browser->webView_name), 0.0, 0.5);
// TODO: make the tab initially look "unvisited" until it's focused
// TODO: gtk's tab scrolling is weird?

View File

@ -73,7 +73,7 @@ typedef struct _CBrowser
//UNDEFINED favicon;
guint security;
gchar* statusMessage; // message from a webView
XbelItem* sessionItem;
KatzeXbelItem* sessionItem;
} CBrowser;
enum

View File

@ -13,7 +13,7 @@
#define __GLOBAL_H__ 1
#include "conf.h"
#include "xbel.h"
#include "../katze/katze.h"
#include <gtk/gtk.h>
@ -23,9 +23,9 @@ CConfig* config;
GList* searchEngines; // Items of type 'SearchEngine'
GList* browsers; // Items of type 'CBrowser'
GtkAccelGroup* accel_group;
XbelItem* bookmarks;
XbelItem* session;
XbelItem* tabtrash;
KatzeXbelItem* bookmarks;
KatzeXbelItem* session;
KatzeXbelItem* tabtrash;
// Custom stock items

View File

@ -241,7 +241,7 @@ void update_favicon(CBrowser* browser)
void update_security(CBrowser* browser)
{
const gchar* uri = xbel_bookmark_get_href(browser->sessionItem);
const gchar* uri = katze_xbel_bookmark_get_href(browser->sessionItem);
// TODO: This check is bogus, until webkit tells us how secure a page is
if(g_str_has_prefix(uri, "https://"))
{
@ -405,7 +405,7 @@ void update_browser_actions(CBrowser* browser)
action_set_sensitive("TabPrevious", active, browser);
action_set_sensitive("TabNext", active, browser);
gboolean tabtrashEmpty = xbel_folder_is_empty(tabtrash);
gboolean tabtrashEmpty = katze_xbel_folder_is_empty(tabtrash);
action_set_sensitive("UndoTabClose", !tabtrashEmpty, browser);
action_set_sensitive("TabsClosed", !tabtrashEmpty, browser);
}

View File

@ -17,7 +17,7 @@
#include "sokoke.h"
#include "search.h"
#include "webView.h"
#include "xbel.h"
#include "../katze/katze.h"
#include <string.h>
#include <gtk/gtk.h>
@ -148,9 +148,9 @@ int main(int argc, char** argv)
}
g_free(configFile);
configFile = g_build_filename(configPath, "bookmarks.xbel", NULL);
bookmarks = xbel_folder_new();
bookmarks = katze_xbel_folder_new();
error = NULL;
if(!xbel_folder_from_file(bookmarks, configFile, &error))
if(!katze_xbel_folder_from_file(bookmarks, configFile, &error))
{
if(error->code != G_FILE_ERROR_NOENT)
g_string_append_printf(errorMessages
@ -158,12 +158,12 @@ int main(int argc, char** argv)
g_error_free(error);
}
g_free(configFile);
XbelItem* _session = xbel_folder_new();
KatzeXbelItem* _session = katze_xbel_folder_new();
if(config->startup == CONFIG_STARTUP_SESSION)
{
configFile = g_build_filename(configPath, "session.xbel", NULL);
error = NULL;
if(!xbel_folder_from_file(_session, configFile, &error))
if(!katze_xbel_folder_from_file(_session, configFile, &error))
{
if(error->code != G_FILE_ERROR_NOENT)
g_string_append_printf(errorMessages
@ -173,9 +173,9 @@ int main(int argc, char** argv)
g_free(configFile);
}
configFile = g_build_filename(configPath, "tabtrash.xbel", NULL);
tabtrash = xbel_folder_new();
tabtrash = katze_xbel_folder_new();
error = NULL;
if(!xbel_folder_from_file(tabtrash, configFile, &error))
if(!katze_xbel_folder_from_file(tabtrash, configFile, &error))
{
if(error->code != G_FILE_ERROR_NOENT)
g_string_append_printf(errorMessages
@ -204,8 +204,8 @@ int main(int argc, char** argv)
{
config_free(config);
search_engines_free(searchEngines);
xbel_item_unref(bookmarks);
xbel_item_unref(_session);
katze_xbel_item_unref(bookmarks);
katze_xbel_item_unref(_session);
g_string_free(errorMessages, TRUE);
return 0;
}
@ -220,23 +220,23 @@ int main(int argc, char** argv)
gchar* uri = argc > 1 ? strtok(g_strdup(argv[1]), "|") : NULL;
while(uri != NULL)
{
XbelItem* item = xbel_bookmark_new();
KatzeXbelItem* item = katze_xbel_bookmark_new();
gchar* uriReady = magic_uri(uri, FALSE);
xbel_bookmark_set_href(item, uriReady);
katze_xbel_bookmark_set_href(item, uriReady);
g_free(uriReady);
xbel_folder_append_item(_session, item);
katze_xbel_folder_append_item(_session, item);
uri = strtok(NULL, "|");
}
g_free(uri);
if(xbel_folder_is_empty(_session))
if(katze_xbel_folder_is_empty(_session))
{
XbelItem* item = xbel_bookmark_new();
KatzeXbelItem* item = katze_xbel_bookmark_new();
if(config->startup == CONFIG_STARTUP_BLANK)
xbel_bookmark_set_href(item, "about:blank");
katze_xbel_bookmark_set_href(item, "about:blank");
else
xbel_bookmark_set_href(item, config->homepage);
xbel_folder_prepend_item(_session, item);
katze_xbel_bookmark_set_href(item, config->homepage);
katze_xbel_folder_prepend_item(_session, item);
}
g_free(configPath);
@ -244,17 +244,17 @@ int main(int argc, char** argv)
stock_items_init();
browsers = NULL;
session = xbel_folder_new();
session = katze_xbel_folder_new();
CBrowser* browser = NULL;
guint n = xbel_folder_get_n_items(_session);
guint n = katze_xbel_folder_get_n_items(_session);
guint i;
for(i = 0; i < n; i++)
{
XbelItem* item = xbel_folder_get_nth_item(_session, i);
KatzeXbelItem* item = katze_xbel_folder_get_nth_item(_session, i);
browser = browser_new(browser);
webView_open(browser->webView, xbel_bookmark_get_href(item));
webView_open(browser->webView, katze_xbel_bookmark_get_href(item));
}
xbel_item_unref(_session);
katze_xbel_item_unref(_session);
gtk_main();
@ -272,34 +272,34 @@ int main(int argc, char** argv)
g_free(configFile);
configFile = g_build_filename(configPath, "bookmarks.xbel", NULL);
error = NULL;
if(!xbel_folder_to_file(bookmarks, configFile, &error))
if(!katze_xbel_folder_to_file(bookmarks, configFile, &error))
{
g_warning("Bookmarks couldn't be saved. %s", error->message);
g_error_free(error);
}
xbel_item_unref(bookmarks);
katze_xbel_item_unref(bookmarks);
g_free(configFile);
configFile = g_build_filename(configPath, "tabtrash.xbel", NULL);
error = NULL;
if(!xbel_folder_to_file(tabtrash, configFile, &error))
if(!katze_xbel_folder_to_file(tabtrash, configFile, &error))
{
g_warning("Tabtrash couldn't be saved. %s", error->message);
g_error_free(error);
}
xbel_item_unref(tabtrash);
katze_xbel_item_unref(tabtrash);
g_free(configFile);
if(config->startup == CONFIG_STARTUP_SESSION)
{
configFile = g_build_filename(configPath, "session.xbel", NULL);
error = NULL;
if(!xbel_folder_to_file(session, configFile, &error))
if(!katze_xbel_folder_to_file(session, configFile, &error))
{
g_warning("Session couldn't be saved. %s", error->message);
g_error_free(error);
}
g_free(configFile);
}
xbel_item_unref(session);
katze_xbel_item_unref(session);
configFile = g_build_filename(configPath, "config", NULL);
error = NULL;
if(!config_to_file(config, configFile, &error))

View File

@ -13,7 +13,7 @@
#include "helpers.h"
#include "sokoke.h"
#include "xbel.h"
#include "../katze/katze.h"
#include <string.h>
@ -39,7 +39,7 @@ void on_webView_title_changed(GtkWidget* webView, WebKitWebFrame* frame
newTitle = title;
else
newTitle = webkit_web_frame_get_uri(frame);
xbel_item_set_title(browser->sessionItem, newTitle);
katze_xbel_item_set_title(browser->sessionItem, newTitle);
gtk_label_set_text(GTK_LABEL(browser->webView_name), newTitle);
sokoke_widget_set_tooltip_text(gtk_widget_get_parent(
gtk_widget_get_parent(browser->webView_name)), newTitle);
@ -90,7 +90,7 @@ void on_webView_load_committed(GtkWidget* webView, WebKitWebFrame* frame
{
const gchar* uri = webkit_web_frame_get_uri(frame);
gchar* newUri = g_strdup(uri ? uri : "");
xbel_bookmark_set_href(browser->sessionItem, newUri);
katze_xbel_bookmark_set_href(browser->sessionItem, newUri);
if(webView == get_nth_webView(-1, browser))
{
gtk_entry_set_text(GTK_ENTRY(browser->location), newUri);
@ -301,9 +301,9 @@ void on_webView_destroy(GtkWidget* widget, CBrowser* browser)
g_object_unref(browser->popup_element);
g_object_unref(browser->popup_editable);
guint i;
guint n = xbel_folder_get_n_items(bookmarks);
guint n = katze_xbel_folder_get_n_items(bookmarks);
for(i = 0; i < n; i++)
xbel_item_unref(xbel_folder_get_nth_item(bookmarks, i));
katze_xbel_item_unref(katze_xbel_folder_get_nth_item(bookmarks, i));
gtk_main_quit();
}
}
@ -329,28 +329,28 @@ void webView_open(GtkWidget* webView, const gchar* uri)
CBrowser* browser = get_browser_from_webView(webView);
if(browser)
{
xbel_bookmark_set_href(browser->sessionItem, uri);
xbel_item_set_title(browser->sessionItem, "");
katze_xbel_bookmark_set_href(browser->sessionItem, uri);
katze_xbel_item_set_title(browser->sessionItem, "");
}
}
void webView_close(GtkWidget* webView, CBrowser* browser)
{
browser = get_browser_from_webView(webView);
const gchar* uri = xbel_bookmark_get_href(browser->sessionItem);
xbel_folder_remove_item(session, browser->sessionItem);
const gchar* uri = katze_xbel_bookmark_get_href(browser->sessionItem);
katze_xbel_folder_remove_item(session, browser->sessionItem);
if(uri && *uri)
{
xbel_folder_prepend_item(tabtrash, browser->sessionItem);
guint n = xbel_folder_get_n_items(tabtrash);
katze_xbel_folder_prepend_item(tabtrash, browser->sessionItem);
guint n = katze_xbel_folder_get_n_items(tabtrash);
if(n > 10)
{
XbelItem* item = xbel_folder_get_nth_item(tabtrash, n - 1);
xbel_item_unref(item);
KatzeXbelItem* item = katze_xbel_folder_get_nth_item(tabtrash, n - 1);
katze_xbel_item_unref(item);
}
}
else
xbel_item_unref(browser->sessionItem);
katze_xbel_item_unref(browser->sessionItem);
gtk_widget_destroy(browser->webView_menu);
gtk_notebook_remove_page(GTK_NOTEBOOK(browser->webViews)
, get_webView_index(webView, browser));

View File

@ -1,825 +0,0 @@
/*
Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
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.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
/**
* This is an implementation of XBEL based on Glib and libXML2.
*
* Design Goals:
* - XbelItem is the only opaque public data structure.
* - The interface should be intuitive and familiar to Glib users.
* - There should be no public exposure of libXML2 specific code.
* - Bookmarks should actually be easily exchangeable between programs.
*
* TODO:
* - Support info > metadata, alias, added, modified, visited
* - Compatibility: The Nokia 770 *requires* metadata and folder
* - Compatibility: Kazehakase's bookmarks
* - Compatibility: Epiphany's bookmarks
* - XML Indentation
* - Export and import to other formats
**/
#include "xbel.h"
#include <stdio.h>
#include <string.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
// Private: Create a new item of a certain type
static XbelItem* xbel_item_new(XbelItemKind kind)
{
XbelItem* item = g_new(XbelItem, 1);
item->refs = 1;
item->parent = NULL;
item->kind = kind;
if(kind == XBEL_ITEM_FOLDER)
{
item->items = NULL;
item->folded = TRUE;
}
if(kind != XBEL_ITEM_SEPARATOR)
{
item->title = NULL;
item->desc = NULL;
}
if(kind == XBEL_ITEM_BOOKMARK)
item->href = g_strdup("");
return item;
}
/**
* xbel_bookmark_new:
*
* Create a new empty bookmark.
*
* Return value: a newly allocated bookmark
**/
XbelItem* xbel_bookmark_new(void)
{
return xbel_item_new(XBEL_ITEM_BOOKMARK);
}
static XbelItem* xbel_bookmark_from_xmlNodePtr(xmlNodePtr cur)
{
g_return_val_if_fail(cur != NULL, NULL);
XbelItem* bookmark = xbel_bookmark_new();
xmlChar* key = xmlGetProp(cur, (xmlChar*)"href");
xbel_bookmark_set_href(bookmark, (gchar*)key);
cur = cur->xmlChildrenNode;
while(cur != NULL)
{
if(!xmlStrcmp(cur->name, (const xmlChar*)"title"))
{
xmlChar* key = xmlNodeGetContent(cur);
bookmark->title = (gchar*)g_strstrip((gchar*)key);
}
else if(!xmlStrcmp(cur->name, (const xmlChar*)"desc"))
{
xmlChar* key = xmlNodeGetContent(cur);
bookmark->desc = (gchar*)g_strstrip((gchar*)key);
}
cur = cur->next;
}
return bookmark;
}
/**
* xbel_separator_new:
*
* Create a new separator.
*
* The returned item must be freed eventually.
*
* Return value: a newly allocated separator.
**/
XbelItem* xbel_separator_new(void)
{
return xbel_item_new(XBEL_ITEM_SEPARATOR);
}
/**
* xbel_folder_new:
*
* Create a new empty folder.
*
* The returned item must be freed eventually.
*
* Return value: a newly allocated folder.
**/
XbelItem* xbel_folder_new(void)
{
return xbel_item_new(XBEL_ITEM_FOLDER);
}
// Private: Create a folder from an xmlNodePtr
static XbelItem* xbel_folder_from_xmlNodePtr(xmlNodePtr cur)
{
g_return_val_if_fail(cur != NULL, NULL);
XbelItem* folder = xbel_folder_new();
xmlChar* key = xmlGetProp(cur, (xmlChar*)"folded");
if(key)
{
if(!g_ascii_strncasecmp((gchar*)key, "yes", 3))
folder->folded = TRUE;
else if(!g_ascii_strncasecmp((gchar*)key, "no", 2))
folder->folded = FALSE;
else
g_warning("XBEL: Unknown value for folded.");
xmlFree(key);
}
cur = cur->xmlChildrenNode;
while(cur)
{
if(!xmlStrcmp(cur->name, (const xmlChar*)"title"))
{
xmlChar* key = xmlNodeGetContent(cur);
folder->title = (gchar*)g_strstrip((gchar*)key);
}
else if(!xmlStrcmp(cur->name, (const xmlChar*)"desc"))
{
xmlChar* key = xmlNodeGetContent(cur);
folder->desc = (gchar*)g_strstrip((gchar*)key);
}
else if(!xmlStrcmp(cur->name, (const xmlChar*)"folder"))
{
XbelItem* item = xbel_folder_from_xmlNodePtr(cur);
item->parent = (struct XbelItem*)folder;
folder->items = g_list_prepend(folder->items, item);
}
else if(!xmlStrcmp(cur->name, (const xmlChar*)"bookmark"))
{
XbelItem* item = xbel_bookmark_from_xmlNodePtr(cur);
item->parent = (struct XbelItem*)folder;
folder->items = g_list_prepend(folder->items, item);
}
else if(!xmlStrcmp(cur->name, (const xmlChar*)"separator"))
{
XbelItem* item = xbel_separator_new();
item->parent = (struct XbelItem*)folder;
folder->items = g_list_prepend(folder->items, item);
}
cur = cur->next;
}
// Prepending and reversing is faster than appending
folder->items = g_list_reverse(folder->items);
return folder;
}
// Private: Loads the contents from an xmlNodePtr into a folder.
static gboolean xbel_folder_from_xmlDocPtr(XbelItem* folder, xmlDocPtr doc)
{
g_return_val_if_fail(xbel_folder_is_empty(folder), FALSE);
g_return_val_if_fail(doc != NULL, FALSE);
xmlNodePtr cur = xmlDocGetRootElement(doc);
xmlChar* version = xmlGetProp(cur, (xmlChar*)"version");
if(xmlStrcmp(version, (xmlChar*)"1.0"))
g_warning("XBEL version is not 1.0.");
xmlFree(version);
folder->title = (gchar*)xmlGetProp(cur, (xmlChar*)"title");
folder->desc = (gchar*)xmlGetProp(cur, (xmlChar*)"desc");
if((cur = xmlDocGetRootElement(doc)) == NULL)
{
// Empty document
return FALSE;
}
if(xmlStrcmp(cur->name, (const xmlChar*)"xbel"))
{
// Wrong document kind
return FALSE;
}
cur = cur->xmlChildrenNode;
while(cur != NULL)
{
XbelItem* item = NULL;
if(!xmlStrcmp(cur->name, (const xmlChar*)"folder"))
item = xbel_folder_from_xmlNodePtr(cur);
else if(!xmlStrcmp(cur->name, (const xmlChar*)"bookmark"))
item = xbel_bookmark_from_xmlNodePtr(cur);
else if(!xmlStrcmp(cur->name, (const xmlChar*)"separator"))
item = xbel_separator_new();
/*else if(!xmlStrcmp(cur->name, (const xmlChar*)"info"))
item = xbel_parse_info(xbel, cur);*/
if(item != NULL)
{
item->parent = (struct XbelItem*)folder;
folder->items = g_list_prepend(folder->items, item);
}
cur = cur->next;
}
// Prepending and reversing is faster than appending
folder->items = g_list_reverse(folder->items);
return TRUE;
}
/**
* xbel_item_ref:
* @item: a valid item
*
* Ref an XbelItem.
*
* Ref means that the reference count is increased by one.
*
* This has no effect on children of a folder.
**/
void xbel_item_ref(XbelItem* item)
{
g_return_if_fail(item);
item->refs++;
}
/**
* xbel_item_unref:
* @item: a valid item
*
* Unref an XbelItem. If @item is a folder all of its children will also
* be unreffed automatically.
*
* Unref means that the reference count is decreased. If there are no
* references left, the memory will be freed and if needed removed from
* its containing folder.
**/
void xbel_item_unref(XbelItem* item)
{
g_return_if_fail(item);
item->refs--;
if(item->refs)
return;
XbelItem* parent = xbel_item_get_parent(item);
if(parent)
xbel_folder_remove_item(parent, item);
if(xbel_item_is_folder(item))
{
guint n = xbel_folder_get_n_items(item);
guint i;
for(i = 0; i < n; i++)
{
XbelItem* _item = xbel_folder_get_nth_item(item, i);
_item->parent = NULL;
xbel_item_unref(_item);
}
g_list_free(item->items);
}
if(item->kind != XBEL_ITEM_SEPARATOR)
{
g_free(item->title);
g_free(item->desc);
}
if(item->kind == XBEL_ITEM_BOOKMARK)
g_free(item->href);
g_free(item);
}
/**
* xbel_item_copy:
* @item: the item to copy
*
* Copy an XbelItem.
*
* The returned item must be unreffed eventually.
*
* Return value: a copy of @item
**/
XbelItem* xbel_item_copy(XbelItem* item)
{
g_return_val_if_fail(item, NULL);
XbelItem* copy = xbel_folder_new();
if(xbel_item_is_folder(item))
{
guint n = xbel_folder_get_n_items(item);
guint i;
for(i = 0; i < n; i++)
{
XbelItem* _item = xbel_folder_get_nth_item(item, i);
xbel_folder_append_item(copy, xbel_item_copy(_item));
}
}
if(item->kind != XBEL_ITEM_SEPARATOR)
{
xbel_item_set_title(copy, item->title);
xbel_item_set_desc(copy, item->desc);
}
if(item->kind == XBEL_ITEM_BOOKMARK)
xbel_bookmark_set_href(copy, item->href);
return copy;
}
GType xbel_item_get_type()
{
static GType type = 0;
if(!type)
type = g_pointer_type_register_static("xbel_item");
return type;
}
/**
* xbel_folder_append_item:
* @folder: a folder
* @item: the item to append
*
* Append the given item to a folder.
*
* The item is actually moved and must not be contained in another folder.
*
**/
void xbel_folder_append_item(XbelItem* folder, XbelItem* item)
{
g_return_if_fail(!xbel_item_get_parent(item));
g_return_if_fail(xbel_item_is_folder(folder));
item->parent = (struct XbelItem*)folder;
folder->items = g_list_append(folder->items, item);
}
/**
* xbel_folder_prepend_item:
* @folder: a folder
* @item: the item to prepend
*
* Prepend the given item to a folder.
*
* The item is actually moved and must not be contained in another folder.
*
**/
void xbel_folder_prepend_item(XbelItem* folder, XbelItem* item)
{
g_return_if_fail(!xbel_item_get_parent(item));
g_return_if_fail(xbel_item_is_folder(folder));
item->parent = (struct XbelItem*)folder;
folder->items = g_list_prepend(folder->items, item);
}
/**
* xbel_folder_remove_item:
* @folder: a folder
* @item: the item to remove
*
* Remove the given @item from a @folder.
**/
void xbel_folder_remove_item(XbelItem* folder, XbelItem* item)
{
g_return_if_fail(item);
g_return_if_fail(xbel_item_get_parent(folder) != item);
item->parent = NULL;
// Fortunately we know that items are unique
folder->items = g_list_remove(folder->items, item);
}
/**
* xbel_folder_get_n_items:
* @folder: a folder
*
* Retrieve the number of items contained in the given @folder.
*
* Return value: number of items
**/
guint xbel_folder_get_n_items(XbelItem* folder)
{
g_return_val_if_fail(xbel_item_is_folder(folder), 0);
return g_list_length(folder->items);
}
/**
* xbel_folder_get_nth_item:
* @folder: a folder
* @n: the index of an item
*
* Retrieve an item contained in the given @folder by its index.
*
* Return value: the item at the given index or %NULL
**/
XbelItem* xbel_folder_get_nth_item(XbelItem* folder, guint n)
{
g_return_val_if_fail(xbel_item_is_folder(folder), NULL);
return (XbelItem*)g_list_nth_data(folder->items, n);
}
/**
* xbel_folder_is_empty:
* @folder: A folder.
*
* Determines wether or not a folder contains no items. This is significantly
* faster than xbel_folder_get_n_items for this particular purpose.
*
* Return value: Wether the given @folder is folded.
**/
gboolean xbel_folder_is_empty(XbelItem* folder)
{
return !xbel_folder_get_nth_item(folder, 0);
}
/**
* xbel_folder_get_folded:
* @folder: A folder.
*
* Determines wether or not a folder is folded. If a folder is not folded
* it should not be exposed in a user interface.
*
* New folders are folded by default.
*
* Return value: Wether the given @folder is folded.
**/
gboolean xbel_folder_get_folded(XbelItem* folder)
{
g_return_val_if_fail(xbel_item_is_folder(folder), TRUE);
return folder->folded;
}
/**
* xbel_item_get_kind:
* @item: A item.
*
* Determines the kind of an item.
*
* Return value: The kind of the given @item.
**/
XbelItemKind xbel_item_get_kind(XbelItem* item)
{
return item->kind;
}
/**
* xbel_item_get_parent:
* @item: A valid item.
*
* Retrieves the parent folder of an item.
*
* Return value: The parent folder of the given @item or %NULL.
**/
XbelItem* xbel_item_get_parent(XbelItem* item)
{
g_return_val_if_fail(item, NULL);
return (XbelItem*)item->parent;
}
/**
* xbel_item_get_title:
* @item: A valid item.
*
* Retrieves the title of an item.
*
* Return value: The title of the given @item or %NULL.
**/
G_CONST_RETURN gchar* xbel_item_get_title(XbelItem* item)
{
g_return_val_if_fail(!xbel_item_is_separator(item), NULL);
return item->title;
}
/**
* xbel_item_get_desc:
* @item: A valid item.
*
* Retrieves the description of an item.
*
* Return value: The description of the @item or %NULL.
**/
G_CONST_RETURN gchar* xbel_item_get_desc(XbelItem* item)
{
g_return_val_if_fail(!xbel_item_is_separator(item), NULL);
return item->desc;
}
/**
* xbel_bookmark_get_href:
* @bookmark: A bookmark.
*
* Retrieves the uri of a bookmark. The value is guaranteed to not be %NULL.
*
* Return value: The uri of the @bookmark.
**/
G_CONST_RETURN gchar* xbel_bookmark_get_href(XbelItem* bookmark)
{
g_return_val_if_fail(xbel_item_is_bookmark(bookmark), NULL);
return bookmark->href;
}
/**
* xbel_item_is_bookmark:
* @item: A valid item.
*
* Determines wether or not an item is a bookmark.
*
* Return value: %TRUE if the @item is a bookmark.
**/
gboolean xbel_item_is_bookmark(XbelItem* item)
{
g_return_val_if_fail(item, FALSE);
return item->kind == XBEL_ITEM_BOOKMARK;
}
/**
* xbel_item_is_separator:
* @item: A valid item.
*
* Determines wether or not an item is a separator.
*
* Return value: %TRUE if the @item is a separator.
**/
gboolean xbel_item_is_separator(XbelItem* item)
{
g_return_val_if_fail(item, FALSE);
return item->kind == XBEL_ITEM_SEPARATOR;
}
/**
* xbel_item_is_folder:
* @item: A valid item.
*
* Determines wether or not an item is a folder.
*
* Return value: %TRUE if the item is a folder.
**/
gboolean xbel_item_is_folder(XbelItem* item)
{
g_return_val_if_fail(item, FALSE);
return item->kind == XBEL_ITEM_FOLDER;
}
/**
* xbel_folder_set_folded:
* @folder: A folder.
* @folded: TRUE if the folder is folded.
*
* Sets the foldedness of the @folder.
**/
void xbel_folder_set_folded(XbelItem* folder, gboolean folded)
{
g_return_if_fail(xbel_item_is_folder(folder));
folder->folded = folded;
}
/**
* xbel_item_set_title:
* @item: A valid item.
* @title: A string to use for the title.
*
* Sets the title of the @item.
**/
void xbel_item_set_title(XbelItem* item, const gchar* title)
{
g_return_if_fail(!xbel_item_is_separator(item));
g_free(item->title);
item->title = g_strdup(title);
}
/**
* xbel_item_set_desc:
* @item: A valid item.
* @title: A string to use for the description.
*
* Sets the description of the @item.
**/
void xbel_item_set_desc(XbelItem* item, const gchar* desc)
{
g_return_if_fail(!xbel_item_is_separator(item));
g_free(item->desc);
item->desc = g_strdup(desc);
}
/**
* xbel_bookmark_set_href:
* @bookmark: A bookmark.
* @href: A string containing a valid uri.
*
* Sets the uri of the bookmark.
*
* The uri must not be %NULL.
*
* This uri is not currently validated in any way. This may change in the future.
**/
void xbel_bookmark_set_href(XbelItem* bookmark, const gchar* href)
{
g_return_if_fail(xbel_item_is_bookmark(bookmark));
g_return_if_fail(href);
g_free(bookmark->href);
bookmark->href = g_strdup(href);
}
gboolean xbel_folder_from_data(XbelItem* folder, const gchar* data, GError** error)
{
g_return_val_if_fail(xbel_folder_is_empty(folder), FALSE);
g_return_val_if_fail(data, FALSE);
xmlDocPtr doc;
if((doc = xmlParseMemory(data, strlen(data))) == NULL)
{
// No valid xml or broken encoding
*error = g_error_new(XBEL_ERROR, XBEL_ERROR_READ
, "Malformed document.");
return FALSE;
}
if(!xbel_folder_from_xmlDocPtr(folder, doc))
{
// Parsing failed
xmlFreeDoc(doc);
*error = g_error_new(XBEL_ERROR, XBEL_ERROR_READ
, "Malformed document.");
return FALSE;
}
xmlFreeDoc(doc);
return TRUE;
}
/**
* xbel_folder_from_file:
* @folder: An empty folder.
* @file: A relative path to a file.
* @error: return location for a GError or %NULL
*
* Tries to load @file.
*
* Return value: %TRUE on success or %FALSE when an error occured.
**/
gboolean xbel_folder_from_file(XbelItem* folder, const gchar* file, GError** error)
{
g_return_val_if_fail(xbel_folder_is_empty(folder), FALSE);
g_return_val_if_fail(file, FALSE);
if(!g_file_test(file, G_FILE_TEST_EXISTS))
{
// File doesn't exist
*error = g_error_new(G_FILE_ERROR, G_FILE_ERROR_NOENT
, "File not found.");
return FALSE;
}
xmlDocPtr doc;
if((doc = xmlParseFile(file)) == NULL)
{
// No valid xml or broken encoding
*error = g_error_new(XBEL_ERROR, XBEL_ERROR_READ
, "Malformed document.");
return FALSE;
}
if(!xbel_folder_from_xmlDocPtr(folder, doc))
{
// Parsing failed
xmlFreeDoc(doc);
*error = g_error_new(XBEL_ERROR, XBEL_ERROR_READ
, "Malformed document.");
return FALSE;
}
xmlFreeDoc(doc);
return TRUE;
}
/**
* xbel_folder_from_data_dirs:
* @folder: An empty folder.
* @file: A relative path to a file.
* @full_path: return location for the full path of the file or %NULL
* @error: return location for a GError or %NULL
*
* Tries to load @file from the user data dir or any of the system data dirs.
*
* Return value: %TRUE on success or %FALSE when an error occured.
**/
gboolean xbel_folder_from_data_dirs(XbelItem* folder, const gchar* file
, gchar** full_path, GError** error)
{
g_return_val_if_fail(xbel_folder_is_empty(folder), FALSE);
g_return_val_if_fail(file, FALSE);
// FIXME: Essentially unimplemented
*error = g_error_new(XBEL_ERROR, XBEL_ERROR_READ
, "Malformed document.");
return FALSE;
}
static gchar* xbel_xml_element(const gchar* name, const gchar* value)
{
if(!value)
return g_strdup("");
gchar* valueEscaped = g_markup_escape_text(value, -1);
gchar* XML = g_strdup_printf("<%s>%s</%s>\n", name, valueEscaped, name);
g_free(valueEscaped);
return XML;
}
static gchar* xbel_item_to_data(XbelItem* item)
{
g_return_val_if_fail(item, NULL);
gchar* XML = NULL;
switch(xbel_item_get_kind(item))
{
case XBEL_ITEM_FOLDER:
{
GString* _XML = g_string_new(NULL);
guint n = xbel_folder_get_n_items(item);
guint i;
for(i = 0; i < n; i++)
{
XbelItem* _item = xbel_folder_get_nth_item(item, i);
gchar* itemXML = xbel_item_to_data(_item);
g_string_append(_XML, itemXML);
g_free(itemXML);
}
gchar* folded = item->folded ? NULL : g_strdup_printf(" folded=\"no\"");
gchar* title = xbel_xml_element("title", item->title);
gchar* desc = xbel_xml_element("desc", item->desc);
XML = g_strdup_printf("<folder%s>\n%s%s%s</folder>\n"
, folded ? folded : ""
, title
, desc
, g_string_free(_XML, FALSE));
g_free(folded);
g_free(title);
g_free(desc);
break;
}
case XBEL_ITEM_BOOKMARK:
{
gchar* hrefEscaped = g_markup_escape_text(item->href, -1);
gchar* href = g_strdup_printf(" href=\"%s\"", hrefEscaped);
g_free(hrefEscaped);
gchar* title = xbel_xml_element("title", item->title);
gchar* desc = xbel_xml_element("desc", item->desc);
XML = g_strdup_printf("<bookmark%s>\n%s%s%s</bookmark>\n"
, href
, title
, desc
, "");
g_free(href);
g_free(title);
g_free(desc);
break;
}
case XBEL_ITEM_SEPARATOR:
XML = g_strdup("<separator/>\n");
break;
default:
g_warning("XBEL: Unknown item kind");
}
return XML;
}
/**
* xbel_folder_to_data:
* @folder: A folder.
* @length: return location for the length of the created string or %NULL
* @error: return location for a GError or %NULL
*
* Retrieve the contents of @folder as a string.
*
* Return value: %TRUE on success or %FALSE when an error occured.
**/
gchar* xbel_folder_to_data(XbelItem* folder, gsize* length, GError** error)
{
g_return_val_if_fail(xbel_item_is_folder(folder), FALSE);
// FIXME: length is never filled
GString* innerXML = g_string_new(NULL);
guint n = xbel_folder_get_n_items(folder);
guint i;
for(i = 0; i < n; i++)
{
gchar* sItem = xbel_item_to_data(xbel_folder_get_nth_item(folder, i));
g_string_append(innerXML, sItem);
g_free(sItem);
}
gchar* title = xbel_xml_element("title", folder->title);
gchar* desc = xbel_xml_element("desc", folder->desc);
gchar* outerXML;
outerXML = g_strdup_printf("%s%s<xbel version=\"1.0\">\n%s%s%s</xbel>\n"
, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
, "<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML\" \"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">\n"
, title
, desc
, g_string_free(innerXML, FALSE));
g_free(title);
g_free(desc);
return outerXML;
}
/**
* xbel_folder_to_file:
* @folder: A folder.
* @file: The destination filename.
* @error: return location for a GError or %NULL
*
* Write the contents of @folder to the specified file, creating it if necessary.
*
* Return value: %TRUE on success or %FALSE when an error occured.
**/
gboolean xbel_folder_to_file(XbelItem* folder, const gchar* file, GError** error)
{
g_return_val_if_fail(file, FALSE);
gchar* data;
if(!(data = xbel_folder_to_data(folder, NULL, error)))
return FALSE;
FILE* fp;
if(!(fp = fopen(file, "w")))
{
*error = g_error_new(G_FILE_ERROR, G_FILE_ERROR_ACCES
, "Writing failed.");
return FALSE;
}
fputs(data, fp);
fclose(fp);
g_free(data);
return TRUE;
}

View File

@ -1,158 +0,0 @@
/*
Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
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.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __XBEL_H__
#define __XBEL_H__ 1
#include <glib.h>
#include <glib-object.h>
#define XBEL_ERROR g_quark_from_string("XBEL_ERROR")
typedef enum
{
XBEL_ERROR_INVALID_URI, /* Malformed uri */
XBEL_ERROR_INVALID_VALUE, /* Requested field not found */
XBEL_ERROR_URI_NOT_FOUND, /* Requested uri not found */
XBEL_ERROR_READ, /* Malformed document */
XBEL_ERROR_UNKNOWN_ENCODING, /* Parsed text was in an unknown encoding */
XBEL_ERROR_WRITE, /* Writing failed. */
} XBELError;
typedef enum
{
XBEL_ITEM_FOLDER,
XBEL_ITEM_BOOKMARK,
XBEL_ITEM_SEPARATOR
} XbelItemKind;
// Note: This structure is entirely private.
typedef struct
{
guint refs;
XbelItemKind kind;
struct XbelItem* parent;
GList* items; // folder
gboolean folded; // foolder
gchar* title; // !separator
gchar* desc; // folder and bookmark
gchar* href; // bookmark
//time_t added; // !separator
//time_t modfied; // bookmark
//time_t visited; // bookmark
} XbelItem;
XbelItem*
xbel_bookmark_new(void);
XbelItem*
xbel_separator_new(void);
XbelItem*
xbel_folder_new(void);
void
xbel_item_ref(XbelItem*);
void
xbel_item_unref(XbelItem*);
XbelItem*
xbel_item_copy(XbelItem*);
GType
xbel_item_get_type();
#define G_TYPE_XBEL_ITEM xbel_item_get_type()
void
xbel_folder_append_item(XbelItem*, XbelItem*);
void
xbel_folder_prepend_item(XbelItem*, XbelItem*);
void
xbel_folder_remove_item(XbelItem*, XbelItem*);
guint
xbel_folder_get_n_items(XbelItem*);
XbelItem*
xbel_folder_get_nth_item(XbelItem*, guint);
gboolean
xbel_folder_is_empty(XbelItem*);
gboolean
xbel_folder_get_folded(XbelItem*);
XbelItemKind
xbel_item_get_kind(XbelItem*);
XbelItem*
xbel_item_get_parent(XbelItem*);
G_CONST_RETURN gchar*
xbel_item_get_title(XbelItem*);
G_CONST_RETURN gchar*
xbel_item_get_desc(XbelItem*);
G_CONST_RETURN gchar*
xbel_bookmark_get_href(XbelItem*);
/*time_t
xbel_bookmark_get_added(XbelItem*);
time_t
xbel_bookmark_get_modified(XbelItem*);
time_t
xbel_bookmark_get_visited(XbelItem*);*/
gboolean
xbel_item_is_bookmark(XbelItem*);
gboolean
xbel_item_is_separator(XbelItem*);
gboolean
xbel_item_is_folder(XbelItem*);
void
xbel_folder_set_folded(XbelItem*, gboolean);
void
xbel_item_set_title(XbelItem*, const gchar*);
void
xbel_item_set_desc(XbelItem*, const gchar*);
void
xbel_bookmark_set_href(XbelItem*, const gchar*);
gboolean
xbel_folder_from_data(XbelItem*, const gchar*, GError**);
gboolean
xbel_folder_from_file(XbelItem*, const gchar*, GError**);
gboolean
xbel_folder_from_data_dirs(XbelItem*, const gchar*, gchar**, GError**);
gchar*
xbel_folder_to_data(XbelItem*, gsize*, GError**);
gboolean
xbel_folder_to_file(XbelItem*, const gchar*, GError**);
#endif /* !__XBEL_H__ */