diff --git a/katze/Makefile.am b/katze/Makefile.am index f0b2a9fb..fd22b389 100644 --- a/katze/Makefile.am +++ b/katze/Makefile.am @@ -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 diff --git a/katze/katze-xbel.c b/katze/katze-xbel.c new file mode 100644 index 00000000..d6a2402d --- /dev/null +++ b/katze/katze-xbel.c @@ -0,0 +1,958 @@ +/* + Copyright (C) 2007-2008 Christian Dywan + + 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 +#include +#include +#include + +#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\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 ("\n%s%s%s\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 ("\n%s%s%s\n", + href, + title, desc, + ""); + g_free (href); + g_free (title); + g_free (desc); + break; + } + case KATZE_XBEL_ITEM_KIND_SEPARATOR: + markup = g_strdup ("\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\n%s%s%s\n", + "\n", + "\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; +} diff --git a/katze/katze-xbel.h b/katze/katze-xbel.h new file mode 100644 index 00000000..78a46855 --- /dev/null +++ b/katze/katze-xbel.h @@ -0,0 +1,176 @@ +/* + Copyright (C) 2007-2008 Christian Dywan + + 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 + +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__ */ diff --git a/katze/katze.h b/katze/katze.h index f401be3c..e0e72c9a 100644 --- a/katze/katze.h +++ b/katze/katze.h @@ -14,5 +14,6 @@ #include "katze-throbber.h" #include "katze-utils.h" +#include "katze-xbel.h" -#endif /* __KATZE_THROBBER_H__ */ +#endif /* __KATZE_H__ */ diff --git a/src/Makefile.am b/src/Makefile.am index 6246932a..2b98976a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/browser.c b/src/browser.c index 8dac19a5..f56ed0f5 100644 --- a/src/browser.c +++ b/src/browser.c @@ -17,7 +17,6 @@ #include "ui.h" #include "webView.h" #include "webSearch.h" -#include "xbel.h" #include "../katze/katze.h" #include @@ -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", "Separator", 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? diff --git a/src/browser.h b/src/browser.h index f25cebd2..6448c4e7 100644 --- a/src/browser.h +++ b/src/browser.h @@ -73,7 +73,7 @@ typedef struct _CBrowser //UNDEFINED favicon; guint security; gchar* statusMessage; // message from a webView - XbelItem* sessionItem; + KatzeXbelItem* sessionItem; } CBrowser; enum diff --git a/src/global.h b/src/global.h index c893d54d..19139f3e 100644 --- a/src/global.h +++ b/src/global.h @@ -13,7 +13,7 @@ #define __GLOBAL_H__ 1 #include "conf.h" -#include "xbel.h" +#include "../katze/katze.h" #include @@ -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 diff --git a/src/helpers.c b/src/helpers.c index 74ed68e6..792b7101 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -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); } diff --git a/src/main.c b/src/main.c index c5456db8..fb79eb97 100755 --- a/src/main.c +++ b/src/main.c @@ -17,7 +17,7 @@ #include "sokoke.h" #include "search.h" #include "webView.h" -#include "xbel.h" +#include "../katze/katze.h" #include #include @@ -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)) diff --git a/src/webView.c b/src/webView.c index 3a8e392b..bef0a0b1 100644 --- a/src/webView.c +++ b/src/webView.c @@ -13,7 +13,7 @@ #include "helpers.h" #include "sokoke.h" -#include "xbel.h" +#include "../katze/katze.h" #include @@ -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)); diff --git a/src/xbel.c b/src/xbel.c deleted file mode 100644 index 07b625da..00000000 --- a/src/xbel.c +++ /dev/null @@ -1,825 +0,0 @@ -/* - Copyright (C) 2007 Christian Dywan - - 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 -#include -#include -#include - -// 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\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("\n%s%s%s\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("\n%s%s%s\n" - , href - , title - , desc - , ""); - g_free(href); - g_free(title); - g_free(desc); - break; - } - case XBEL_ITEM_SEPARATOR: - XML = g_strdup("\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\n%s%s%s\n" - , "\n" - , "\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; -} diff --git a/src/xbel.h b/src/xbel.h deleted file mode 100644 index 2fb6bf40..00000000 --- a/src/xbel.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - Copyright (C) 2007 Christian Dywan - - 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 -#include - -#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__ */