midori/midori/midori-bookmarks-db.c

1152 lines
32 KiB
C

/*
Copyright (C) 2010 Christian Dywan <christian@twotoasts.de>
Copyright (C) 2010 Alexander Butenko <a.butenka@gmail.com>
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.
*/
#include "midori-bookmarks-db.h"
#include "midori-app.h"
#include "midori-array.h"
#include "sokoke.h"
#include "midori-core.h"
#include <glib/gstdio.h>
#include <glib/gi18n.h>
#include <config.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
/**
* SECTION:midory-bookmarks-db
* @short_description: A #KatzeArray connected to a database
* @see_also: #KatzeArray
*
* #MidoriBookmarksDb is a #KatzeArray specialized for database
* interraction.
*/
struct _MidoriBookmarksDb
{
KatzeArray parent_instance;
sqlite3* db;
GHashTable* all_items;
};
struct _MidoriBookmarksDbClass
{
KatzeArrayClass parent_class;
/* Signals */
void
(*update_item) (MidoriBookmarksDb* bookmarks,
gpointer item);
};
G_DEFINE_TYPE (MidoriBookmarksDb, midori_bookmarks_db, KATZE_TYPE_ARRAY);
enum {
UPDATE_ITEM,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static void
_midori_bookmarks_db_add_item (KatzeArray* array,
gpointer item);
static void
_midori_bookmarks_db_update_item (MidoriBookmarksDb* bookmarks,
gpointer item);
static void
_midori_bookmarks_db_remove_item (KatzeArray* array,
gpointer item);
static void
_midori_bookmarks_db_move_item (KatzeArray* array,
gpointer item,
gint position);
static void
_midori_bookmarks_db_clear (KatzeArray* array);
static void
midori_bookmarks_db_finalize (GObject* object);
static gint64
midori_bookmarks_db_insert_item_db (sqlite3* db,
KatzeItem* item,
gint64 parentid);
static gboolean
midori_bookmarks_db_update_item_db (sqlite3* db,
KatzeItem* item);
static gboolean
midori_bookmarks_db_remove_item_db (sqlite3* db,
KatzeItem* item);
static guint
item_hash (gconstpointer item)
{
gint64 id = katze_item_get_meta_integer (KATZE_ITEM (item), "id");
return g_int64_hash (&id);
}
static gboolean
item_equal (gconstpointer item_a, gconstpointer item_b)
{
gint64 id_a = katze_item_get_meta_integer (KATZE_ITEM (item_a), "id");
gint64 id_b = katze_item_get_meta_integer (KATZE_ITEM (item_b), "id");
return (id_a == id_b)? TRUE : FALSE;
}
static void
midori_bookmarks_db_class_init (MidoriBookmarksDbClass* class)
{
GObjectClass* gobject_class;
KatzeArrayClass* katze_array_class;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_bookmarks_db_finalize;
signals[UPDATE_ITEM] = g_signal_new (
"update-item",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
G_STRUCT_OFFSET (MidoriBookmarksDbClass, update_item),
0,
NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1,
G_TYPE_POINTER);
katze_array_class = KATZE_ARRAY_CLASS (class);
katze_array_class->add_item = _midori_bookmarks_db_add_item;
katze_array_class->remove_item = _midori_bookmarks_db_remove_item;
katze_array_class->move_item = _midori_bookmarks_db_move_item;
katze_array_class->clear = _midori_bookmarks_db_clear;
class->update_item = _midori_bookmarks_db_update_item;
}
static void
midori_bookmarks_db_init (MidoriBookmarksDb* bookmarks)
{
bookmarks->db = NULL;
bookmarks->all_items = g_hash_table_new (item_hash, item_equal);
katze_item_set_meta_integer (KATZE_ITEM (bookmarks), "id", -1);
katze_item_set_name (KATZE_ITEM (bookmarks), _("Bookmarks"));
g_hash_table_insert (bookmarks->all_items, bookmarks, bookmarks);
/* g_object_ref (bookmarks); */
}
static void
midori_bookmarks_db_finalize (GObject* object)
{
MidoriBookmarksDb* bookmarks = MIDORI_BOOKMARKS_DB (object);
if (bookmarks->db)
{
sqlite3_close (bookmarks->db);
}
g_hash_table_unref (bookmarks->all_items);
G_OBJECT_CLASS (midori_bookmarks_db_parent_class)->finalize (object);
}
/**
* midori_bookmarks_db_get_item_parent:
* @bookmarks: the main bookmarks array
* @item: a #KatzeItem
*
* Internal function that find the parent of the @item thanks to its %parentid
**/
static KatzeArray*
midori_bookmarks_db_get_item_parent (MidoriBookmarksDb* bookmarks,
gpointer item)
{
gint64 parentid = katze_item_get_meta_integer (KATZE_ITEM (item), "parentid");
KatzeItem *search = katze_item_new ();
KatzeArray* parent;
if (!parentid)
{
parentid = katze_item_get_meta_integer (KATZE_ITEM (bookmarks), "id");
katze_item_set_meta_integer (KATZE_ITEM (item), "parentid", parentid);
}
katze_item_set_meta_integer(search, "id", parentid);
parent = KATZE_ARRAY (g_hash_table_lookup (bookmarks->all_items, search));
g_object_unref (search);
if (!parent)
{
parent = KATZE_ARRAY (bookmarks);
katze_item_set_meta_integer (KATZE_ITEM (item), "parentid",
katze_item_get_meta_integer (KATZE_ITEM (bookmarks), "id"));
}
return parent;
}
/**
* _midori_bookmarks_db_add_item:
* @array: the main bookmarks array
* @item: a #KatzeItem
*
* Internal function that overloads the #KatzeArray %katze_array_add_item().
* It relays the add item to the appropriate #KatzeArray.
**/
static void
_midori_bookmarks_db_add_item (KatzeArray* array,
gpointer item)
{
MidoriBookmarksDb *bookmarks;
KatzeArray* parent;
KatzeArray* db_parent;
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (array));
g_return_if_fail (KATZE_IS_ITEM (item));
bookmarks = MIDORI_BOOKMARKS_DB (array);
parent = katze_item_get_parent (KATZE_ITEM (item));
db_parent = midori_bookmarks_db_get_item_parent (bookmarks, item);
if (parent == db_parent)
{
if (IS_MIDORI_BOOKMARKS_DB (parent))
KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->update (parent);
else if (KATZE_IS_ARRAY (parent))
katze_array_update (parent);
return;
}
if (IS_MIDORI_BOOKMARKS_DB (db_parent))
KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->add_item (db_parent, item);
else if (KATZE_IS_ARRAY (db_parent))
katze_array_add_item (db_parent, item);
g_assert (db_parent == katze_item_get_parent (KATZE_ITEM (item)));
}
/**
* _midori_bookmarks_db_update_item:
* @array: the main bookmarks array
* @item: a #KatzeItem
*
* Internal function that implements the %midori_bookmarks_db_update_item() post-processing.
* It relays an update to the appropriate #KatzeArray.
**/
static void
_midori_bookmarks_db_update_item (MidoriBookmarksDb* bookmarks,
gpointer item)
{
KatzeArray* parent;
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
g_return_if_fail (KATZE_IS_ITEM (item));
parent = katze_item_get_parent (KATZE_ITEM (item));
g_return_if_fail (parent);
if (IS_MIDORI_BOOKMARKS_DB (parent))
KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->update (parent);
else
katze_array_update (parent);
}
/**
* _midori_bookmarks_db_remove_item:
* @array: the main bookmarks array
* @item: a #KatzeItem
*
* Internal function that overloads the #KatzeArray %katze_array_remove_item().
* It relays the remove item to the appropriate #KatzeArray.
**/
static void
_midori_bookmarks_db_remove_item (KatzeArray* array,
gpointer item)
{
KatzeArray* parent;
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (array));
g_return_if_fail (KATZE_IS_ITEM (item));
parent = katze_item_get_parent (KATZE_ITEM (item));
g_return_if_fail (parent);
if (IS_MIDORI_BOOKMARKS_DB (parent))
KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->remove_item (parent, item);
else if (KATZE_IS_ARRAY (parent))
katze_array_remove_item (parent, item);
}
/**
* _midori_bookmarks_db_move_item:
* @array: the main bookmarks array
* @item: a #KatzeItem
* @position: the new @item position
*
* Internal function that overloads the #KatzeArray %katze_array_move_item().
* It relays the move @item to the appropriate #KatzeArray.
**/
static void
_midori_bookmarks_db_move_item (KatzeArray* array,
gpointer item,
gint position)
{
KatzeArray* parent;
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (array));
g_return_if_fail (KATZE_IS_ITEM (item));
parent = katze_item_get_parent (KATZE_ITEM (item));
g_return_if_fail (parent);
KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->move_item (parent, item, position);
}
/**
* _midori_bookmarks_db_clear:
* @array: the main bookmarks array
*
* Internal function that overloads the #KatzeArray %katze_array_clear().
* It deletes the whole bookmarks data.
**/
static void
_midori_bookmarks_db_clear (KatzeArray* array)
{
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (array));
g_critical ("_midori_bookmarks_db_clear: not implemented\n");
}
/**
* midori_bookmarks_db_signal_update_item:
* @array: a #KatzeArray
* @item: an item
*
* Notify an update of the item of the array.
*
**/
static void
midori_bookmarks_db_signal_update_item (MidoriBookmarksDb* array,
gpointer item)
{
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (array));
g_signal_emit (array, signals[UPDATE_ITEM], 0, item);
}
/**
* midori_bookmarks_db_add_item_recursive:
* @item: the removed #KatzeItem
* @bookmarks : the main bookmarks array
*
* Internal function that creates memory records of the added @item.
* If @item is a #KatzeArray, the function recursiveley adds records
* of all its childs.
**/
static gint
midori_bookmarks_db_add_item_recursive (MidoriBookmarksDb* bookmarks,
KatzeItem* item)
{
GList* list;
KatzeArray* array;
gint64 id = 0;
gint count = 0;
gint64 parentid = katze_item_get_meta_integer (item, "parentid");
id = midori_bookmarks_db_insert_item_db (bookmarks->db, item, parentid);
count++;
g_object_ref (item);
g_hash_table_insert (bookmarks->all_items, item, item);
if (!KATZE_IS_ARRAY (item))
return count;
array = KATZE_ARRAY (item);
KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
{
katze_item_set_meta_integer (item, "parentid", id);
count += midori_bookmarks_db_add_item_recursive (bookmarks, item);
}
g_list_free (list);
return count;
}
/**
* midori_bookmarks_db_remove_item_recursive:
* @item: the removed #KatzeItem
* @bookmarks : the main bookmarks array
*
* Internal function that removes memory records of the removed @item.
* If @item is a #KatzeArray, the function recursiveley removes records
* of all its childs.
**/
static void
midori_bookmarks_db_remove_item_recursive (KatzeItem* item,
MidoriBookmarksDb* bookmarks)
{
gpointer found;
KatzeArray* array;
KatzeItem* child;
GList* list;
if (NULL != (found = g_hash_table_lookup (bookmarks->all_items, item)))
{
g_hash_table_remove (bookmarks->all_items, found);
g_object_unref (found);
}
if (!KATZE_IS_ARRAY (item))
return;
array = KATZE_ARRAY (item);
KATZE_ARRAY_FOREACH_ITEM_L (child, array, list)
{
midori_bookmarks_db_remove_item_recursive (child, bookmarks);
}
g_list_free (list);
}
/**
* midori_bookmarks_db_insert_item_db:
* @db: the #sqlite3
* @item: #KatzeItem the item to insert
*
* Internal function that does the actual SQL INSERT of the @item in @db.
*
* Since: 0.5.2
**/
static gint64
midori_bookmarks_db_insert_item_db (sqlite3* db,
KatzeItem* item,
gint64 parentid)
{
gchar* sqlcmd;
char* errmsg = NULL;
KatzeItem* old_parent;
gchar* new_parentid;
gchar* id = NULL;
const gchar* uri = NULL;
const gchar* desc = NULL;
gint64 seq = 0;
/* Bookmarks must have a name, import may produce invalid items */
g_return_val_if_fail (katze_item_get_name (item), seq);
if (!db)
return seq;
if (katze_item_get_meta_integer (item, "id") > 0)
id = g_strdup_printf ("%" G_GINT64_FORMAT, katze_item_get_meta_integer(item, "id"));
else
id = g_strdup_printf ("NULL");
if (KATZE_ITEM_IS_BOOKMARK (item))
uri = katze_item_get_uri (item);
if (katze_item_get_text (item))
desc = katze_item_get_text (item);
/* Use folder, otherwise fallback to parent folder */
old_parent = katze_item_get_parent (item);
if (parentid > 0)
new_parentid = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);
else if (old_parent && katze_item_get_meta_integer (old_parent, "id") > 0)
new_parentid = g_strdup_printf ("%" G_GINT64_FORMAT, katze_item_get_meta_integer (old_parent, "id"));
else
new_parentid = g_strdup_printf ("NULL");
sqlcmd = sqlite3_mprintf (
"INSERT INTO bookmarks (id, parentid, title, uri, desc, toolbar, app) "
"VALUES (%q, %q, '%q', '%q', '%q', %d, %d)",
id,
new_parentid,
katze_item_get_name (item),
katze_str_non_null (uri),
katze_str_non_null (desc),
katze_item_get_meta_boolean (item, "toolbar"),
katze_item_get_meta_boolean (item, "app"));
if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) == SQLITE_OK)
{
/* Get insert id */
if (g_str_equal (id, "NULL"))
{
KatzeArray* seq_array;
sqlite3_free (sqlcmd);
sqlcmd = sqlite3_mprintf (
"SELECT seq FROM sqlite_sequence WHERE name = 'bookmarks'");
seq_array = katze_array_from_sqlite (db, sqlcmd);
if (katze_array_get_nth_item (seq_array, 0))
{
KatzeItem* seq_item = katze_array_get_nth_item (seq_array, 0);
seq = katze_item_get_meta_integer (seq_item, "seq");
katze_item_set_meta_integer (item, "id", seq);
}
g_object_unref (seq_array);
}
}
else
{
g_printerr (_("Failed to add bookmark item: %s\n"), errmsg);
sqlite3_free (errmsg);
}
sqlite3_free (sqlcmd);
g_free (new_parentid);
g_free (id);
return seq;
}
/**
* midori_bookmarks_db_update_item_db:
* @db: the #sqlite3
* @item: #KatzeItem the item to update
*
* Internal function that does the actual SQL UPDATE of the @item in @db.
*
* Since: 0.5.2
**/
static gboolean
midori_bookmarks_db_update_item_db (sqlite3* db,
KatzeItem* item)
{
gchar* sqlcmd;
char* errmsg = NULL;
gchar* parentid;
gboolean updated;
gchar* id;
id = g_strdup_printf ("%" G_GINT64_FORMAT,
katze_item_get_meta_integer (item, "id"));
if (katze_item_get_meta_integer (item, "parentid") > 0)
parentid = g_strdup_printf ("%" G_GINT64_FORMAT,
katze_item_get_meta_integer (item, "parentid"));
else
parentid = g_strdup_printf ("NULL");
sqlcmd = sqlite3_mprintf (
"UPDATE bookmarks SET "
"parentid=%q, title='%q', uri='%q', desc='%q', toolbar=%d, app=%d "
"WHERE id = %q ;",
parentid,
katze_item_get_name (item),
katze_str_non_null (katze_item_get_uri (item)),
katze_str_non_null (katze_item_get_meta_string (item, "desc")),
katze_item_get_meta_boolean (item, "toolbar"),
katze_item_get_meta_boolean (item, "app"),
id);
updated = TRUE;
if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) != SQLITE_OK)
{
updated = FALSE;
g_printerr (_("Failed to update bookmark: %s\n"), errmsg);
sqlite3_free (errmsg);
}
sqlite3_free (sqlcmd);
g_free (parentid);
g_free (id);
return updated;
}
/**
* midori_bookmarks_db_remove_item_db:
* @db: the #sqlite3
* @item: #KatzeItem the item to delete
*
* Internal function that does the actual SQL DELETE of the @item in @db.
*
* Since: 0.5.2
**/
static gboolean
midori_bookmarks_db_remove_item_db (sqlite3* db,
KatzeItem* item)
{
char* errmsg = NULL;
gchar* sqlcmd;
gboolean removed = TRUE;
gchar* id;
id = g_strdup_printf ("%" G_GINT64_FORMAT,
katze_item_get_meta_integer (item, "id"));
sqlcmd = sqlite3_mprintf ("DELETE FROM bookmarks WHERE id = %q", id);
if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) != SQLITE_OK)
{
g_printerr (_("Failed to remove bookmark item: %s\n"), errmsg);
sqlite3_free (errmsg);
removed = FALSE;
}
sqlite3_free (sqlcmd);
g_free (id);
return removed;
}
/**
* midori_bookmarks_db_add_item:
* @bookmarks: the main bookmark array
* @item: #KatzeItem the item to update
*
* Adds the @item in the bookmark data base.
*
* Since: 0.5.2
**/
void
midori_bookmarks_db_add_item (MidoriBookmarksDb* bookmarks, KatzeItem* item)
{
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
g_return_if_fail (KATZE_IS_ITEM (item));
g_return_if_fail (NULL == katze_item_get_meta_string (item, "id"));
midori_bookmarks_db_add_item_recursive (bookmarks, item);
katze_array_add_item (KATZE_ARRAY (bookmarks), item);
}
/**
* midori_bookmarks_db_update_item:
* @bookmarks: the main bookmark array
* @item: #KatzeItem the item to update
*
* Updates the @item in the bookmark data base.
*
* Since: 0.5.2
**/
void
midori_bookmarks_db_update_item (MidoriBookmarksDb* bookmarks, KatzeItem* item)
{
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
g_return_if_fail (KATZE_IS_ITEM (item));
g_return_if_fail (katze_item_get_meta_string (item, "id"));
g_return_if_fail (0 != katze_item_get_meta_integer (item, "id"));
midori_bookmarks_db_update_item_db (bookmarks->db, item);
midori_bookmarks_db_signal_update_item (bookmarks, item);
}
/**
* midori_bookmarks_db_remove_item:
* @bookmarks: the main bookmark array
* @item: #KatzeItem the item to remove
*
* Removes the @item from the bookmark data base.
*
* Since: 0.5.2
**/
void
midori_bookmarks_db_remove_item (MidoriBookmarksDb* bookmarks, KatzeItem* item)
{
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
g_return_if_fail (KATZE_IS_ITEM (item));
g_return_if_fail (katze_item_get_meta_string (item, "id"));
g_return_if_fail (0 != katze_item_get_meta_integer (item, "id"));
midori_bookmarks_db_remove_item_recursive (item, bookmarks);
midori_bookmarks_db_remove_item_db (bookmarks->db, item);
katze_array_remove_item (KATZE_ARRAY (bookmarks), item);
}
/**
* midori_bookmarks_db_new:
*
* Initializes the bookmark data base.
*
* Returns: the main bookmarks array
*
* Since: 0.5.2
**/
MidoriBookmarksDb*
midori_bookmarks_db_new (char** errmsg)
{
MidoriBookmarksDatabase* database;
GError* error = NULL;
sqlite3* db;
MidoriBookmarksDb* bookmarks;
g_return_val_if_fail (errmsg != NULL, NULL);
database = midori_bookmarks_database_new (&error);
if (error != NULL)
{
*errmsg = g_strdup (error->message);
g_error_free (error);
return NULL;
}
db = midori_database_get_db (MIDORI_DATABASE (database));
g_return_val_if_fail (db != NULL, NULL);
bookmarks = MIDORI_BOOKMARKS_DB (g_object_new (TYPE_MIDORI_BOOKMARKS_DB,
"type", KATZE_TYPE_ITEM,
NULL));
bookmarks->db = db;
g_object_set_data (G_OBJECT (bookmarks), "db", db);
return bookmarks;
}
/**
* midori_bookmarks_db_on_quit:
* @bookmarks: the main bookmark array
*
* Delete the main bookmark array.
*
* Since: 0.5.2
**/
void
midori_bookmarks_db_on_quit (MidoriBookmarksDb* bookmarks)
{
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
g_object_unref (bookmarks);
}
/**
* midori_bookmarks_db_import_array:
* @bookmarks: the main bookmark array
* @array: #KatzeArray containing the items to import
* @parentid: the id of folder
*
* Imports the items of @array as children of the folder
* identfied by @parentid.
*
* Since: 0.5.2
**/
void
midori_bookmarks_db_import_array (MidoriBookmarksDb* bookmarks,
KatzeArray* array,
gint64 parentid)
{
GList* list;
KatzeItem* item;
g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
g_return_if_fail (KATZE_IS_ARRAY (array));
KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
{
/* IDs coming from previously exported database must be forgotten */
katze_item_set_meta_integer (item, "id", -1);
katze_item_set_meta_integer (item, "parentid", parentid);
midori_bookmarks_db_add_item (bookmarks, item);
}
g_list_free (list);
}
/**
* midori_bookmarks_db_array_from_statement:
* @stmt: the sqlite returned statement
* @bookmarks: the database controller
*
* Internal function that populate a #KatzeArray by processing the @stmt
* rows identifying:
* a- if the item is already in memory
* in this case the item data is updated with retreived database content
* and the already existing item is populated in the returned #KatzeArray
* b- if the data is a folder
* a new #KatzeArray item is populated in the returned #KatzeArray and
* memorized for future use.
* c- if the data is a bookmark
* a new #KatzeItem item is populated in the returned #KatzeArray and
* memorized for furure use.
*
* Return value: the populated #KatzeArray
**/
static KatzeArray*
midori_bookmarks_db_array_from_statement (sqlite3_stmt* stmt,
MidoriBookmarksDb* bookmarks)
{
KatzeArray *array;
gint result;
gint cols;
array = katze_array_new (KATZE_TYPE_ITEM);
cols = sqlite3_column_count (stmt);
while ((result = sqlite3_step (stmt)) == SQLITE_ROW)
{
gint i;
KatzeItem* item;
gpointer found;
item = katze_item_new ();
for (i = 0; i < cols; i++)
katze_item_set_value_from_column (stmt, i, item);
if (NULL != (found = g_hash_table_lookup (bookmarks->all_items, item)))
{
for (i = 0; i < cols; i++)
katze_item_set_value_from_column (stmt, i, found);
g_object_unref (item);
item = found;
}
else if (KATZE_ITEM_IS_FOLDER (item))
{
g_object_unref (item);
item = KATZE_ITEM (katze_array_new (KATZE_TYPE_ITEM));
for (i = 0; i < cols; i++)
katze_item_set_value_from_column (stmt, i, item);
g_object_ref (item);
g_hash_table_insert (bookmarks->all_items, item, item);
}
else
{
g_object_ref (item);
g_hash_table_insert (bookmarks->all_items, item, item);
}
katze_array_add_item (array, item);
}
sqlite3_clear_bindings (stmt);
sqlite3_reset (stmt);
return array;
}
/**
* midori_bookmarks_db_array_from_sqlite:
* @array: the main bookmark array
* @sqlcmd: the sqlcmd to execute
*
* Internal function that process the requested @sqlcmd.
*
* Return value: a #KatzeArray on success, %NULL otherwise
**/
static KatzeArray*
midori_bookmarks_db_array_from_sqlite (MidoriBookmarksDb* bookmarks,
const gchar* sqlcmd)
{
sqlite3_stmt* stmt;
gint result;
g_return_val_if_fail (bookmarks->db != NULL, NULL);
result = sqlite3_prepare_v2 (bookmarks->db, sqlcmd, -1, &stmt, NULL);
if (result != SQLITE_OK)
return NULL;
return midori_bookmarks_db_array_from_statement (stmt, bookmarks);
}
/**
* midori_bookmarks_db_query_recursive:
* @bookmarks: the main bookmark array
* @fields: comma separated list of fields
* @condition: condition, like "folder = '%q'"
* @value: a value to be inserted if @condition contains %q
* @recursive: if %TRUE include children
*
* Stores the result in a #KatzeArray.
*
* Return value: a #KatzeArray on success, %NULL otherwise
*
* Since: 0.5.2
**/
KatzeArray*
midori_bookmarks_db_query_recursive (MidoriBookmarksDb* bookmarks,
const gchar* fields,
const gchar* condition,
const gchar* value,
gboolean recursive)
{
gchar* sqlcmd;
char* sqlcmd_value;
KatzeArray* array;
KatzeItem* item;
GList* list;
g_return_val_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks), NULL);
g_return_val_if_fail (fields, NULL);
g_return_val_if_fail (condition, NULL);
sqlcmd = g_strdup_printf ("SELECT %s FROM bookmarks WHERE %s "
"ORDER BY (uri='') ASC, title DESC", fields, condition);
if (strstr (condition, "%q"))
{
sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");
array = midori_bookmarks_db_array_from_sqlite (bookmarks, sqlcmd_value);
sqlite3_free (sqlcmd_value);
}
else
array = midori_bookmarks_db_array_from_sqlite (bookmarks, sqlcmd);
g_free (sqlcmd);
if (!recursive)
return array;
KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
{
if (KATZE_ITEM_IS_FOLDER (item))
{
gchar* parentid = g_strdup_printf ("%" G_GINT64_FORMAT,
katze_item_get_meta_integer (item, "id"));
KatzeArray* subarray = midori_bookmarks_db_query_recursive (bookmarks,
fields, "parentid=%q", parentid, TRUE);
KatzeItem* subitem;
GList* sublist;
katze_array_clear (KATZE_ARRAY (item));
KATZE_ARRAY_FOREACH_ITEM_L (subitem, subarray, sublist)
{
katze_array_add_item (KATZE_ARRAY (item), subitem);
}
g_object_unref (subarray);
g_free (parentid);
}
}
g_list_free (list);
return array;
}
static gint64
midori_bookmarks_db_count_from_sqlite (sqlite3* db,
const gchar* sqlcmd)
{
gint64 count = -1;
sqlite3_stmt* stmt;
gint result;
result = sqlite3_prepare_v2 (db, sqlcmd, -1, &stmt, NULL);
if (result != SQLITE_OK)
return -1;
g_assert (sqlite3_column_count (stmt) == 1);
if ((result = sqlite3_step (stmt)) == SQLITE_ROW)
count = sqlite3_column_int64(stmt, 0);
sqlite3_clear_bindings (stmt);
sqlite3_reset (stmt);
return count;
}
static gint64
midori_bookmarks_db_count_recursive_by_id (MidoriBookmarksDb* bookmarks,
const gchar* condition,
const gchar* value,
gint64 id,
gboolean recursive)
{
gint64 count = -1;
gchar* sqlcmd;
char* sqlcmd_value;
sqlite3_stmt* stmt;
gint result;
GList* ids;
GList* iter_ids;
g_return_val_if_fail (condition, -1);
g_return_val_if_fail (MIDORI_BOOKMARKS_DB (bookmarks), -1);
g_return_val_if_fail (bookmarks->db != NULL, -1);
g_assert(!strstr("parentid", condition));
if (id > 0)
sqlcmd = g_strdup_printf ("SELECT COUNT(*) FROM bookmarks "
"WHERE parentid = %" G_GINT64_FORMAT " AND %s",
id,
condition);
else
sqlcmd = g_strdup_printf ("SELECT COUNT(*) FROM bookmarks "
"WHERE parentid IS NULL AND %s ",
condition);
if (strstr (condition, "%q"))
{
sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");
count = midori_bookmarks_db_count_from_sqlite (bookmarks->db, sqlcmd_value);
sqlite3_free (sqlcmd_value);
}
else
count = midori_bookmarks_db_count_from_sqlite (bookmarks->db, sqlcmd);
g_free (sqlcmd);
if (!recursive || (count < 0))
return count;
ids = NULL;
if (id > 0)
sqlcmd_value = sqlite3_mprintf (
"SELECT id FROM bookmarks "
"WHERE parentid = %" G_GINT64_FORMAT " AND uri = ''", id);
else
sqlcmd_value = sqlite3_mprintf (
"SELECT id FROM bookmarks "
"WHERE parentid IS NULL AND uri = ''");
if (sqlite3_prepare_v2 (bookmarks->db, sqlcmd_value, -1, &stmt, NULL) == SQLITE_OK)
{
g_assert (sqlite3_column_count (stmt) == 1);
if ((result = sqlite3_step (stmt)) == SQLITE_ROW)
{
gint64* pid = g_new (gint64, 1);
*pid = sqlite3_column_int64(stmt, 0);
ids = g_list_append (ids, pid);
}
sqlite3_clear_bindings (stmt);
sqlite3_reset (stmt);
}
sqlite3_free (sqlcmd_value);
iter_ids = ids;
while (iter_ids)
{
gint64 sub_count = midori_bookmarks_db_count_recursive_by_id (bookmarks,
condition,
value,
*(gint64*)(iter_ids->data),
recursive);
if (sub_count < 0)
{
g_list_free_full (ids, g_free);
return -1;
}
count += sub_count;
iter_ids = g_list_next (iter_ids);
}
g_list_free_full (ids, g_free);
return count;
}
/**
* midori_bookmarks_db_count_recursive:
* @bookmarks: the main bookmark array
* @condition: condition, like "folder = '%q'"
* @value: a value to be inserted if @condition contains %q
* @recursive: if %TRUE include children
*
* Return value: the number of elements on success, -1 otherwise
*
* Since: 0.5.2
**/
gint64
midori_bookmarks_db_count_recursive (MidoriBookmarksDb* bookmarks,
const gchar* condition,
const gchar* value,
KatzeItem* folder,
gboolean recursive)
{
gint64 id = -1;
g_return_val_if_fail (!folder || KATZE_ITEM_IS_FOLDER (folder), -1);
id = folder ? katze_item_get_meta_integer (folder, "id") : 0;
return midori_bookmarks_db_count_recursive_by_id (bookmarks, condition,
value, id,
recursive);
}
/**
* midori_bookmarks_db_populate_folder:
**/
void
midori_bookmarks_db_populate_folder (MidoriBookmarksDb* bookmarks,
KatzeArray *folder)
{
const gchar* id = katze_item_get_meta_string (KATZE_ITEM (folder), "id");
const gchar *condition;
KatzeArray* array;
KatzeItem* item;
GList* list;
if (id == NULL)
{
condition = "parentid is NULL";
}
else
{
condition = "parentid = %q";
}
array = midori_bookmarks_db_query_recursive (bookmarks,
"id, title, parentid, uri, app, pos_panel, pos_bar", condition, id, FALSE);
if (IS_MIDORI_BOOKMARKS_DB (folder))
{
KATZE_ARRAY_FOREACH_ITEM_L (item, folder, list)
{
KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->remove_item (folder, item);
}
KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
{
KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->add_item (folder, item);
}
}
else
{
katze_array_clear(folder);
KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
{
katze_array_add_item (folder, item);
}
}
g_object_unref (array);
}