Bookmarks: Database structure improved

The new format uses bookmarks_v2.db.

We require sqlite 3.6.19 now due to foreign keys.

Fixes: https://bugs.launchpad.net/midori/+bug/836707
This commit is contained in:
Oliver Hanraths 2012-06-16 01:06:58 +02:00 committed by Christian Dywan
parent bc37926516
commit f840f0508c
8 changed files with 524 additions and 151 deletions

View File

@ -434,7 +434,6 @@ midori_history_clear_cb (KatzeArray* array,
static gboolean
midori_history_initialize (KatzeArray* array,
const gchar* filename,
const gchar* bookmarks_filename,
char** errmsg)
{
sqlite3* db;
@ -442,6 +441,9 @@ midori_history_initialize (KatzeArray* array,
sqlite3_stmt* stmt;
gint result;
gchar* sql;
gchar* bookmarks_filename;
g_return_val_if_fail (errmsg != NULL, FALSE);
if (sqlite3_open (filename, &db) != SQLITE_OK)
{
@ -493,7 +495,9 @@ midori_history_initialize (KatzeArray* array,
"COMMIT;",
NULL, NULL, errmsg);
bookmarks_filename = build_config_filename ("bookmarks_v2.db");
sql = g_strdup_printf ("ATTACH DATABASE '%s' AS bookmarks", bookmarks_filename);
g_free (bookmarks_filename);
sqlite3_exec (db, sql, NULL, NULL, errmsg);
g_free (sql);
g_object_set_data (G_OBJECT (array), "db", db);
@ -1900,9 +1904,7 @@ main (int argc,
gchar** extensions;
MidoriWebSettings* settings;
gchar* config_file;
gchar* bookmarks_file;
GKeyFile* speeddial;
gboolean bookmarks_exist;
MidoriStartup load_on_startup;
KatzeArray* search_engines;
KatzeArray* bookmarks;
@ -2347,10 +2349,8 @@ main (int argc,
midori_startup_timer ("Search read: \t%f");
bookmarks = katze_array_new (KATZE_TYPE_ARRAY);
bookmarks_file = g_build_filename (config, "bookmarks.db", NULL);
bookmarks_exist = g_access (bookmarks_file, F_OK) == 0;
errmsg = NULL;
if ((db = midori_bookmarks_initialize (bookmarks, bookmarks_file, &errmsg)) == NULL)
if ((db = midori_bookmarks_initialize (bookmarks, &errmsg)) == NULL)
{
g_string_append_printf (error_messages,
_("Bookmarks couldn't be loaded: %s\n"), errmsg);
@ -2396,13 +2396,12 @@ main (int argc,
katze_assign (config_file, g_build_filename (config, "history.db", NULL));
errmsg = NULL;
if (!midori_history_initialize (history, config_file, bookmarks_file, &errmsg))
if (!midori_history_initialize (history, config_file, &errmsg))
{
g_string_append_printf (error_messages,
_("The history couldn't be loaded: %s\n"), errmsg);
errmsg = NULL;
}
g_free (bookmarks_file);
midori_startup_timer ("History read: \t%f");
error = NULL;

View File

@ -982,24 +982,26 @@ katze_item_set_value_from_column (sqlite3_stmt* stmt,
item->added = date;
}
else if (g_str_equal (name, "day") || g_str_equal (name, "app")
|| g_str_equal (name, "toolbar"))
|| g_str_equal (name, "toolbar") || g_str_equal (name, "id")
|| g_str_equal (name, "parentid") || g_str_equal (name, "seq")
|| g_str_equal (name, "pos_panel") || g_str_equal (name, "pos_bar"))
{
gint value;
value = sqlite3_column_int64 (stmt, column);
katze_item_set_meta_integer (item, name, value);
}
else if (g_str_equal (name, "folder"))
{
const unsigned char* folder;
folder = sqlite3_column_text (stmt, column);
katze_item_set_meta_string (item, name, (gchar*)folder);
}
else if (g_str_equal (name, "desc"))
{
const unsigned char* text;
text = sqlite3_column_text (stmt, column);
item->text = g_strdup ((gchar*)text);
}
else if (g_str_equal (name, "sql"))
{
const unsigned char* sql;
sql = sqlite3_column_text (stmt, column);
katze_item_set_meta_string (item, name, (gchar*)sql);
}
else
g_warn_if_reached ();
}
@ -1102,7 +1104,7 @@ midori_array_query_recursive (KatzeArray* bookmarks,
return NULL;
sqlcmd = g_strdup_printf ("SELECT %s FROM bookmarks WHERE %s "
"ORDER BY title DESC", fields, condition);
"ORDER BY (uri='') ASC, title DESC", fields, condition);
if (strstr (condition, "%q"))
{
sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");
@ -1120,10 +1122,14 @@ midori_array_query_recursive (KatzeArray* bookmarks,
{
if (KATZE_ITEM_IS_FOLDER (item))
{
gchar* parentid = g_strdup_printf ("%" G_GINT64_FORMAT,
katze_item_get_meta_integer (item, "id"));
KatzeArray* subarray = midori_array_query_recursive (bookmarks,
fields, "folder='%q'", item->name, TRUE);
fields, "parentid=%q", parentid, TRUE);
katze_item_set_name (KATZE_ITEM (subarray), item->name);
katze_array_add_item (array, subarray);
g_free (parentid);
}
}
g_list_free (list);

View File

@ -13,7 +13,9 @@
#include "midori-bookmarks.h"
#include "panels/midori-bookmarks.h"
#include "midori-array.h"
#include "sokoke.h"
#include <glib/gstdio.h>
#include <glib/gi18n.h>
#ifdef G_ENABLE_DEBUG
@ -29,7 +31,7 @@ midori_bookmarks_add_item_cb (KatzeArray* array,
sqlite3* db)
{
midori_bookmarks_insert_item_db (db, item,
katze_item_get_meta_string (item, "folder"));
katze_item_get_meta_integer (item, "parentid"));
}
void
@ -40,19 +42,10 @@ midori_bookmarks_remove_item_cb (KatzeArray* array,
gchar* sqlcmd;
char* errmsg = NULL;
if (KATZE_ITEM_IS_BOOKMARK (item))
sqlcmd = sqlite3_mprintf (
"DELETE FROM bookmarks WHERE uri = '%q' "
" AND folder = '%q'",
katze_item_get_uri (item),
katze_str_non_null (katze_item_get_meta_string (item, "folder")));
else
sqlcmd = sqlite3_mprintf (
"DELETE FROM bookmarks WHERE title = '%q'"
" AND folder = '%q'",
katze_item_get_name (item),
katze_str_non_null (katze_item_get_meta_string (item, "folder")));
sqlcmd = sqlite3_mprintf (
"DELETE FROM bookmarks WHERE id = %" G_GINT64_FORMAT ";",
katze_item_get_meta_integer (item, "id"));
if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) != SQLITE_OK)
{
@ -63,20 +56,102 @@ midori_bookmarks_remove_item_cb (KatzeArray* array,
sqlite3_free (sqlcmd);
}
#define _APPEND_TO_SQL_ERRORMSG(custom_errmsg) \
do { \
if (sql_errmsg) \
{ \
g_string_append_printf (errmsg_str, "%s : %s\n", custom_errmsg, sql_errmsg); \
sqlite3_free (sql_errmsg); \
} \
else \
g_string_append (errmsg_str, custom_errmsg); \
} while (0)
gboolean
midori_bookmarks_import_from_old_db (sqlite3* db,
const gchar* oldfile,
gchar** errmsg)
{
gint sql_errcode;
gboolean failure = FALSE;
gchar* sql_errmsg = NULL;
GString* errmsg_str = g_string_new (NULL);
gchar* attach_stmt = sqlite3_mprintf ("ATTACH DATABASE %Q AS old_db;", oldfile);
const gchar* convert_stmts =
"BEGIN TRANSACTION;"
"INSERT INTO main.bookmarks (parentid, title, uri, desc, app, toolbar) "
"SELECT NULL AS parentid, title, uri, desc, app, toolbar "
"FROM old_db.bookmarks;"
"UPDATE main.bookmarks SET parentid = ("
"SELECT id FROM main.bookmarks AS b1 WHERE b1.title = ("
"SELECT folder FROM old_db.bookmarks WHERE title = main.bookmarks.title));"
"COMMIT;";
const gchar* detach_stmt = "DETACH DATABASE old_db;";
*errmsg = NULL;
sql_errcode = sqlite3_exec (db, attach_stmt, NULL, NULL, &sql_errmsg);
sqlite3_free (attach_stmt);
if (sql_errcode != SQLITE_OK)
{
_APPEND_TO_SQL_ERRORMSG (_("failed to ATTACH old db"));
goto convert_failed;
}
if (sqlite3_exec (db, convert_stmts, NULL, NULL, &sql_errmsg) != SQLITE_OK)
{
failure = TRUE;
_APPEND_TO_SQL_ERRORMSG (_("failed to import from old db"));
/* try to get back to previous state */
if (sqlite3_exec (db, "ROLLBACK TRANSACTION;", NULL, NULL, &sql_errmsg) != SQLITE_OK)
_APPEND_TO_SQL_ERRORMSG (_("failed to rollback the transaction"));
}
if (sqlite3_exec (db, detach_stmt, NULL, NULL, &sql_errmsg) != SQLITE_OK)
_APPEND_TO_SQL_ERRORMSG (_("failed to DETACH "));
if (failure)
{
convert_failed:
*errmsg = g_string_free (errmsg_str, FALSE);
g_print ("ERRORR: %s\n", errmsg_str->str);
return FALSE;
}
return TRUE;
}
#undef _APPEND_TO_SQL_ERRORMSG
sqlite3*
midori_bookmarks_initialize (KatzeArray* array,
const gchar* filename,
char** errmsg)
{
sqlite3* db;
gchar* oldfile;
gchar* newfile;
gboolean newfile_did_exist, oldfile_exists;
const gchar* create_stmt;
gchar* sql_errmsg = NULL;
gchar* import_errmsg = NULL;
if (sqlite3_open (filename, &db) != SQLITE_OK)
g_return_val_if_fail (errmsg != NULL, NULL);
oldfile = g_build_filename (sokoke_set_config_dir (NULL), "bookmarks.db", NULL);
oldfile_exists = g_access (oldfile, F_OK) == 0;
newfile = g_build_filename (sokoke_set_config_dir (NULL), "bookmarks_v2.db", NULL);
newfile_did_exist = g_access (newfile, F_OK) == 0;
/* sqlite3_open will create the file if it did not exists already */
if (sqlite3_open (newfile, &db) != SQLITE_OK)
{
if (errmsg)
*errmsg = g_strdup_printf (_("Failed to open database: %s\n"),
sqlite3_errmsg (db));
sqlite3_close (db);
return NULL;
if (db)
*errmsg = g_strdup_printf (_("failed to open database: %s\n"),
sqlite3_errmsg (db));
else
*errmsg = g_strdup (_("failed to open database\n"));
goto init_failed;
}
#ifdef G_ENABLE_DEBUG
@ -84,17 +159,155 @@ midori_bookmarks_initialize (KatzeArray* array,
sqlite3_trace (db, midori_bookmarks_dbtracer, NULL);
#endif
if (sqlite3_exec (db,
"CREATE TABLE IF NOT EXISTS "
"bookmarks (uri text, title text, folder text, "
"desc text, app integer, toolbar integer);",
NULL, NULL, errmsg) != SQLITE_OK)
create_stmt = /* Table structure */
"CREATE TABLE IF NOT EXISTS bookmarks "
"(id INTEGER PRIMARY KEY AUTOINCREMENT, "
"parentid INTEGER DEFAULT NULL, "
"title TEXT, uri TEXT, desc TEXT, app INTEGER, toolbar INTEGER, "
"pos_panel INTEGER, pos_bar INTEGER, "
"created DATE DEFAULT CURRENT_TIMESTAMP, "
"last_visit DATE, visit_count INTEGER DEFAULT 0, "
"nick TEXT, "
"FOREIGN KEY(parentid) REFERENCES bookmarks(id) "
"ON DELETE CASCADE); PRAGMA foreign_keys = ON;"
/* trigger: insert panel position */
"CREATE TRIGGER IF NOT EXISTS bookmarkInsertPosPanel "
"AFTER INSERT ON bookmarks FOR EACH ROW "
"BEGIN UPDATE bookmarks SET pos_panel = ("
"SELECT ifnull(MAX(pos_panel),0)+1 FROM bookmarks WHERE "
"(NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
"OR (NEW.parentid IS NULL AND parentid IS NULL)) "
"WHERE id = NEW.id; END;"
/* trigger: insert Bookmarkbar position */
"CREATE TRIGGER IF NOT EXISTS bookmarkInsertPosBar "
"AFTER INSERT ON bookmarks FOR EACH ROW WHEN NEW.toolbar=1 "
"BEGIN UPDATE bookmarks SET pos_bar = ("
"SELECT ifnull(MAX(pos_bar),0)+1 FROM bookmarks WHERE "
"((NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
"OR (NEW.parentid IS NULL AND parentid IS NULL)) AND toolbar=1) "
"WHERE id = NEW.id; END;"
/* trigger: update panel position */
"CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosPanel "
"BEFORE UPDATE OF parentid ON bookmarks FOR EACH ROW "
"WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL) "
"AND NEW.parentid IS NOT OLD.parentid) OR "
"((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL) "
"AND NEW.parentid!=OLD.parentid) "
"BEGIN UPDATE bookmarks SET pos_panel = pos_panel-1 "
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_panel > OLD.pos_panel; "
"UPDATE bookmarks SET pos_panel = ("
"SELECT ifnull(MAX(pos_panel),0)+1 FROM bookmarks "
"WHERE (NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
"OR (NEW.parentid IS NULL AND parentid IS NULL)) "
"WHERE id = OLD.id; END;"
/* trigger: update Bookmarkbar position */
"CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosBar0 "
"AFTER UPDATE OF parentid, toolbar ON bookmarks FOR EACH ROW "
"WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL) "
"AND NEW.parentid IS NOT OLD.parentid) "
"OR ((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL) "
"AND NEW.parentid!=OLD.parentid) OR (OLD.toolbar=1 AND NEW.toolbar=0) "
"BEGIN UPDATE bookmarks SET pos_bar = NULL WHERE id = NEW.id; "
"UPDATE bookmarks SET pos_bar = pos_bar-1 "
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_bar > OLD.pos_bar; END;"
/* trigger: update Bookmarkbar position */
"CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosBar1 "
"BEFORE UPDATE OF parentid, toolbar ON bookmarks FOR EACH ROW "
"WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL) "
"AND NEW.parentid IS NOT OLD.parentid) OR "
"((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL) "
"AND NEW.parentid!=OLD.parentid) OR (OLD.toolbar=0 AND NEW.toolbar=1) "
"BEGIN UPDATE bookmarks SET pos_bar = ("
"SELECT ifnull(MAX(pos_bar),0)+1 FROM bookmarks WHERE "
"(NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
"OR (NEW.parentid IS NULL AND parentid IS NULL)) "
"WHERE id = OLD.id; END;"
/* trigger: delete panel position */
"CREATE TRIGGER IF NOT EXISTS bookmarkDeletePosPanel "
"AFTER DELETE ON bookmarks FOR EACH ROW "
"BEGIN UPDATE bookmarks SET pos_panel = pos_panel-1 "
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_panel > OLD.pos_panel; END;"
/* trigger: delete Bookmarkbar position */
"CREATE TRIGGER IF NOT EXISTS bookmarkDeletePosBar "
"AFTER DELETE ON bookmarks FOR EACH ROW WHEN OLD.toolbar=1 "
"BEGIN UPDATE bookmarks SET pos_bar = pos_bar-1 "
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_bar > OLD.pos_bar; END;";
if (newfile_did_exist)
{
/* we are done */
goto init_success;
}
else
{
/* initial creation */
if (sqlite3_exec (db, create_stmt, NULL, NULL, &sql_errmsg) != SQLITE_OK)
{
if (errmsg)
{
if (sql_errmsg)
{
*errmsg = g_strdup_printf (_("could not create bookmarks table: %s\n"), sql_errmsg);
sqlite3_free (sql_errmsg);
}
else
*errmsg = g_strdup (_("could not create bookmarks table"));
}
/* we can as well remove the new file */
g_unlink (newfile);
goto init_failed;
}
}
if (oldfile_exists)
/* import from old db */
if (!midori_bookmarks_import_from_old_db (db, oldfile, &import_errmsg))
{
if (errmsg)
{
if (import_errmsg)
{
*errmsg = g_strdup_printf (_("could not import from old database: %s\n"), import_errmsg);
g_free (import_errmsg);
}
else
*errmsg = g_strdup_printf (_("could not import from old database"));
}
}
init_success:
g_free (newfile);
g_free (oldfile);
g_signal_connect (array, "add-item",
G_CALLBACK (midori_bookmarks_add_item_cb), db);
g_signal_connect (array, "remove-item",
G_CALLBACK (midori_bookmarks_remove_item_cb), db);
return db;
init_failed:
g_free (newfile);
g_free (oldfile);
if (db)
sqlite3_close (db);
return NULL;
g_signal_connect (array, "add-item",
G_CALLBACK (midori_bookmarks_add_item_cb), db);
g_signal_connect (array, "remove-item",
G_CALLBACK (midori_bookmarks_remove_item_cb), db);
return db;
}
void
@ -112,5 +325,5 @@ midori_bookmarks_import (const gchar* filename,
g_error_free (error);
return;
}
midori_bookmarks_import_array_db (db, bookmarks, "");
midori_bookmarks_import_array_db (db, bookmarks, 0);
}

View File

@ -25,7 +25,6 @@ midori_bookmarks_remove_item_cb (KatzeArray* array,
sqlite3*
midori_bookmarks_initialize (KatzeArray* array,
const gchar* filename,
char** errmsg);
void

View File

@ -173,7 +173,11 @@ midori_browser_get_property (GObject* object,
void
midori_bookmarks_import_array_db (sqlite3* db,
KatzeArray* array,
gchar* folder);
gint64 parentid);
gboolean
midori_bookmarks_update_item_db (sqlite3* db,
KatzeItem* item);
void
midori_browser_open_bookmark (MidoriBrowser* browser,
@ -659,9 +663,10 @@ midori_view_notify_statusbar_text_cb (GtkWidget* view,
}
static GtkWidget*
midori_bookmark_folder_button_new (KatzeArray* array,
gboolean new_bookmark,
const gchar* selected)
midori_bookmark_folder_button_new (KatzeArray* array,
gboolean new_bookmark,
gint64 selected,
gint64 parentid)
{
GtkListStore* model;
GtkWidget* combo;
@ -670,16 +675,16 @@ midori_bookmark_folder_button_new (KatzeArray* array,
sqlite3* db;
sqlite3_stmt* statement;
gint result;
const gchar* sqlcmd = "SELECT title from bookmarks where uri=''";
const gchar* sqlcmd = "SELECT title, id FROM bookmarks WHERE uri='' ORDER BY title ASC";
model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT64);
combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (model));
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer, "text", 0);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer, "ellipsize", 1);
gtk_list_store_insert_with_values (model, NULL, G_MAXINT,
0, _("Toplevel folder"), 1, PANGO_ELLIPSIZE_END, -1);
0, _("Toplevel folder"), 1, PANGO_ELLIPSIZE_END, 2, (gint64)0, -1);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
db = g_object_get_data (G_OBJECT (array), "db");
@ -689,34 +694,45 @@ midori_bookmark_folder_button_new (KatzeArray* array,
while ((result = sqlite3_step (statement)) == SQLITE_ROW)
{
const unsigned char* name = sqlite3_column_text (statement, 0);
gtk_list_store_insert_with_values (model, NULL, G_MAXINT,
0, name, 1, PANGO_ELLIPSIZE_END, -1);
if (!new_bookmark && !g_strcmp0 (selected, (gchar*)name))
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), n);
n++;
gint64 id = sqlite3_column_int64 (statement, 1);
/* do not show the folder itself */
if (id != selected)
{
gtk_list_store_insert_with_values (model, NULL, G_MAXINT,
0, name, 1, PANGO_ELLIPSIZE_END, 2, id, -1);
if (!new_bookmark && id == parentid)
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), n);
n++;
}
}
if (n < 2)
gtk_widget_set_sensitive (combo, FALSE);
return combo;
}
static gchar*
static gint64
midori_bookmark_folder_button_get_active (GtkWidget* combo)
{
gchar* selected = NULL;
gint64 id;
GtkTreeIter iter;
g_return_val_if_fail (GTK_IS_COMBO_BOX (combo), NULL);
g_return_val_if_fail (GTK_IS_COMBO_BOX (combo), 0);
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
{
gchar* selected = NULL;
GtkTreeModel* model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &selected, -1);
gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &selected, 2, &id, -1);
if (g_str_equal (selected, _("Toplevel folder")))
katze_assign (selected, g_strdup (""));
id = 0;
g_free (selected);
}
return selected;
return id;
}
static void
@ -861,7 +877,8 @@ midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
gtk_size_group_add_widget (sizegroup, label);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
combo_folder = midori_bookmark_folder_button_new (browser->bookmarks,
new_bookmark, katze_item_get_meta_string (bookmark, "folder"));
new_bookmark, katze_item_get_meta_integer (bookmark, "id"),
katze_item_get_meta_integer (bookmark, "parentid"));
gtk_box_pack_start (GTK_BOX (hbox), combo_folder, TRUE, TRUE, 0);
gtk_container_add (GTK_CONTAINER (content_area), hbox);
gtk_widget_show_all (hbox);
@ -912,10 +929,7 @@ midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
{
gchar* selected;
if (!new_bookmark)
katze_array_remove_item (browser->bookmarks, bookmark);
gint64 selected;
katze_item_set_name (bookmark,
gtk_entry_get_text (GTK_ENTRY (entry_title)));
@ -930,13 +944,16 @@ midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
}
selected = midori_bookmark_folder_button_get_active (combo_folder);
katze_item_set_meta_string (bookmark, "folder", selected);
katze_array_add_item (browser->bookmarks, bookmark);
katze_item_set_meta_integer (bookmark, "parentid", selected);
if (new_bookmark)
katze_array_add_item (browser->bookmarks, bookmark);
else
midori_bookmarks_update_item_db (db, bookmark);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_toolbar)))
if (!gtk_widget_get_visible (browser->bookmarkbar))
_action_set_active (browser, "Bookmarkbar", TRUE);
g_free (selected);
return_status = TRUE;
}
if (gtk_widget_get_visible (browser->bookmarkbar))
@ -3041,14 +3058,35 @@ _action_bookmarks_populate_folder (GtkAction* action,
KatzeArray* folder,
MidoriBrowser* browser)
{
const gchar* folder_name;
gint64 id;
KatzeArray* bookmarks;
GtkWidget* menuitem;
folder_name = katze_item_get_name (KATZE_ITEM (folder));
if (!(bookmarks = midori_array_query (browser->bookmarks,
"uri, title, app, folder", "folder = '%q'", folder_name)))
return FALSE;
id = katze_item_get_meta_integer (KATZE_ITEM (folder), "id");
if (id == -1)
{
if (!(bookmarks = midori_array_query (browser->bookmarks,
"id, title, parentid, uri, app, pos_panel, pos_bar", "parentid is NULL", NULL)))
{
g_warning ("midori_array_query returned NULL)");
return FALSE;
}
}
else
{
gchar *parentid = g_strdup_printf ("%" G_GINT64_FORMAT, id);
if (!(bookmarks = midori_array_query (browser->bookmarks,
"id, title, parentid, uri, app, pos_panel, pos_bar", "parentid = %q", parentid)))
{
g_warning ("midori_array_query returned NULL (id='%s')", parentid);
g_free (parentid);
return FALSE;
}
g_free (parentid);
}
/* Clear items from dummy array here */
gtk_container_foreach (GTK_CONTAINER (menu),
@ -4365,7 +4403,7 @@ _action_bookmarks_import_activate (GtkAction* action,
gtk_size_group_add_widget (sizegroup, label);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
combobox_folder = midori_bookmark_folder_button_new (browser->bookmarks,
FALSE, NULL);
FALSE, 0, 0);
gtk_box_pack_start (GTK_BOX (hbox), combobox_folder, TRUE, TRUE, 0);
gtk_container_add (GTK_CONTAINER (content_area), hbox);
gtk_widget_show_all (hbox);
@ -4375,7 +4413,7 @@ _action_bookmarks_import_activate (GtkAction* action,
{
GtkTreeIter iter;
gchar* path = NULL;
gchar* selected = NULL;
gint64 selected;
GError* error;
sqlite3* db = g_object_get_data (G_OBJECT (browser->bookmarks), "db");
@ -4408,7 +4446,6 @@ _action_bookmarks_import_activate (GtkAction* action,
midori_bookmarks_import_array_db (db, bookmarks, selected);
katze_array_update (browser->bookmarks);
g_object_unref (bookmarks);
g_free (selected);
g_free (path);
}
else
@ -4465,7 +4502,7 @@ wrong_format:
error = NULL;
bookmarks = midori_array_query_recursive (browser->bookmarks,
"*", "folder='%q'", "", TRUE);
"*", "parentid IS NULL", NULL, TRUE);
if (!midori_array_to_file (bookmarks, path, format, &error))
{
sokoke_message_dialog (GTK_MESSAGE_ERROR,
@ -7044,9 +7081,10 @@ midori_bookmarkbar_populate (MidoriBrowser* browser)
gtk_separator_tool_item_new (), -1);
array = midori_array_query (browser->bookmarks,
"uri, title, desc, app, folder, toolbar", "toolbar = 1", NULL);
"id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "toolbar = 1", NULL);
if (!array)
{
g_warning ("midori_array_query returned NULL");
_action_set_sensitive (browser, "BookmarkAdd", FALSE);
_action_set_sensitive (browser, "BookmarkFolderAdd", FALSE);
return;
@ -7058,10 +7096,22 @@ midori_bookmarkbar_populate (MidoriBrowser* browser)
midori_bookmarkbar_insert_item (browser->bookmarkbar, item);
else
{
gint64 id = katze_item_get_meta_integer (item, "id");
gchar* parentid = g_strdup_printf ("%" G_GINT64_FORMAT, id);
KatzeArray* subfolder = midori_array_query (browser->bookmarks,
"uri, title, desc, app", "folder = '%q' AND uri != ''", katze_item_get_name (item));
katze_item_set_name (KATZE_ITEM (subfolder), katze_item_get_name (item));
midori_bookmarkbar_insert_item (browser->bookmarkbar, KATZE_ITEM (subfolder));
"id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid = %q AND uri != ''",
parentid);
if (subfolder)
{
katze_item_set_name (KATZE_ITEM (subfolder), katze_item_get_name (item));
katze_item_set_meta_integer (KATZE_ITEM (subfolder), "id", id);
midori_bookmarkbar_insert_item (browser->bookmarkbar, KATZE_ITEM (subfolder));
}
else
g_warning ("midori_array_query returned NULL (id='%s')", parentid);
g_free (parentid);
}
}
_action_set_sensitive (browser, "BookmarkAdd", TRUE);

View File

@ -120,66 +120,87 @@ midori_bookmarks_get_stock_id (MidoriViewable* viewable)
return STOCK_BOOKMARKS;
}
/* TODO: Function never used */
void
midori_bookmarks_export_array_db (sqlite3* db,
KatzeArray* array,
const gchar* folder)
midori_bookmarks_export_array_db (sqlite3* db,
KatzeArray* array,
gint64 parentid)
{
KatzeArray* root_array;
KatzeArray* subarray;
KatzeItem* item;
GList* list;
gchar* parent_id;
if (!(root_array = midori_array_query (array, "*", "folder='%q'", folder)))
parent_id = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);
if (!(root_array = midori_array_query (array, "*", "parentid = %q", parent_id)))
{
g_free (parent_id);
return;
}
KATZE_ARRAY_FOREACH_ITEM_L (item, root_array, list)
{
if (KATZE_ITEM_IS_FOLDER (item))
{
subarray = katze_array_new (KATZE_TYPE_ARRAY);
katze_item_set_name (KATZE_ITEM (subarray), katze_item_get_name (item));
midori_bookmarks_export_array_db (db, subarray, katze_item_get_name (item));
midori_bookmarks_export_array_db (db, subarray,
katze_item_get_meta_integer (item, "parentid"));
katze_array_add_item (array, subarray);
}
else
katze_array_add_item (array, item);
}
g_free (parent_id);
g_list_free (list);
}
void
midori_bookmarks_import_array_db (sqlite3* db,
KatzeArray* array,
const gchar* folder)
midori_bookmarks_import_array_db (sqlite3* db,
KatzeArray* array,
gint64 parentid)
{
GList* list;
KatzeItem* item;
gint64 id;
if (!db)
return;
KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
{
id = midori_bookmarks_insert_item_db (db, item, parentid);
if (KATZE_IS_ARRAY (item))
midori_bookmarks_import_array_db (db, KATZE_ARRAY (item), folder);
midori_bookmarks_insert_item_db (db, item, folder);
midori_bookmarks_import_array_db (db, KATZE_ARRAY (item), id);
}
g_list_free (list);
}
static KatzeArray*
midori_bookmarks_read_from_db (MidoriBookmarks* bookmarks,
const gchar* folder,
gint64 parentid,
const gchar* keyword)
{
KatzeArray* array;
if (keyword && *keyword)
array = midori_array_query (bookmarks->array,
"uri, title, desc, app, toolbar, folder", "title LIKE '%%%q%%'", keyword);
"id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "title LIKE '%%%q%%'", keyword);
else
array = midori_array_query (bookmarks->array,
"uri, title, desc, app, toolbar, folder", "folder = '%q'", folder);
{
if (parentid > 0)
{
gchar* parent_id = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);
array = midori_array_query (bookmarks->array,
"id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid = %q", parent_id);
g_free (parent_id);
}
else
array = midori_array_query (bookmarks->array,
"id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid IS NULL", NULL);
}
return array ? array : katze_array_new (KATZE_TYPE_ITEM);
}
@ -187,7 +208,7 @@ static void
midori_bookmarks_read_from_db_to_model (MidoriBookmarks* bookmarks,
GtkTreeStore* model,
GtkTreeIter* parent,
const gchar* folder,
gint64 parentid,
const gchar* keyword)
{
KatzeArray* array;
@ -195,7 +216,7 @@ midori_bookmarks_read_from_db_to_model (MidoriBookmarks* bookmarks,
KatzeItem* item;
GtkTreeIter child;
array = midori_bookmarks_read_from_db (bookmarks, folder, keyword);
array = midori_bookmarks_read_from_db (bookmarks, parentid, keyword);
katze_bookmark_populate_tree_view (array, model, parent);
/* Remove invisible dummy row */
last = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), parent);
@ -209,23 +230,30 @@ midori_bookmarks_read_from_db_to_model (MidoriBookmarks* bookmarks,
g_object_unref (item);
}
void
midori_bookmarks_insert_item_db (sqlite3* db,
KatzeItem* item,
const gchar* folder)
gint64
midori_bookmarks_insert_item_db (sqlite3* db,
KatzeItem* item,
gint64 parentid)
{
gchar* sqlcmd;
char* errmsg = NULL;
KatzeItem* old_parent;
const gchar* 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_if_fail (katze_item_get_name (item));
g_return_val_if_fail (katze_item_get_name (item), seq);
if (!db)
return;
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);
@ -235,30 +263,57 @@ midori_bookmarks_insert_item_db (sqlite3* db,
/* Use folder, otherwise fallback to parent folder */
old_parent = katze_item_get_parent (item);
if (folder && *folder)
parent = folder;
else if (old_parent && katze_item_get_name (old_parent))
parent = katze_item_get_name (old_parent);
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
parent = "";
new_parentid = g_strdup_printf ("NULL");
sqlcmd = sqlite3_mprintf (
"INSERT into bookmarks (uri, title, desc, folder, toolbar, app) values"
" ('%q', '%q', '%q', '%q', %d, %d)",
uri ? uri : "",
"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),
desc ? desc : "",
parent,
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)
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;
}
static void
@ -268,15 +323,9 @@ midori_bookmarks_add_item_cb (KatzeArray* array,
{
GtkTreeModel* model;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
if (!g_strcmp0 (katze_item_get_meta_string (item, "folder"), ""))
gtk_tree_store_insert_with_values (GTK_TREE_STORE (model),
NULL, NULL, G_MAXINT, 0, item, -1);
else
{
gtk_tree_store_clear (GTK_TREE_STORE (model));
midori_bookmarks_read_from_db_to_model (bookmarks,
GTK_TREE_STORE (model), NULL, NULL, bookmarks->filter);
}
gtk_tree_store_clear (GTK_TREE_STORE (model));
midori_bookmarks_read_from_db_to_model (bookmarks,
GTK_TREE_STORE (model), NULL, 0, bookmarks->filter);
}
static void
@ -287,7 +336,7 @@ midori_bookmarks_remove_item_cb (KatzeArray* array,
GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
gtk_tree_store_clear (GTK_TREE_STORE (model));
midori_bookmarks_read_from_db_to_model (bookmarks,
GTK_TREE_STORE (model), NULL, NULL, bookmarks->filter);
GTK_TREE_STORE (model), NULL, 0, bookmarks->filter);
}
static void
@ -297,7 +346,7 @@ midori_bookmarks_update_cb (KatzeArray* array,
GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
gtk_tree_store_clear (GTK_TREE_STORE (model));
midori_bookmarks_read_from_db_to_model (bookmarks,
GTK_TREE_STORE (model), NULL, NULL, bookmarks->filter);
GTK_TREE_STORE (model), NULL, 0, bookmarks->filter);
}
@ -310,7 +359,7 @@ midori_bookmarks_row_changed_cb (GtkTreeModel* model,
KatzeItem* item;
GtkTreeIter parent;
KatzeItem* new_parent = NULL;
const gchar* parent_name;
gint64 parentid;
gtk_tree_model_get (model, iter, 0, &item, -1);
@ -320,15 +369,15 @@ midori_bookmarks_row_changed_cb (GtkTreeModel* model,
/* Bookmarks must not be moved into non-folder items */
if (!KATZE_ITEM_IS_FOLDER (new_parent))
parent_name = "";
parentid = 0;
else
parent_name = katze_item_get_name (new_parent);
parentid = katze_item_get_meta_integer (new_parent, "id");
}
else
parent_name = "";
parentid = 0;
katze_array_remove_item (bookmarks->array, item);
katze_item_set_meta_string (item, "folder", parent_name);
katze_item_set_meta_integer (item, "parentid", parentid);
katze_array_add_item (bookmarks->array, item);
g_object_unref (item);
@ -359,14 +408,24 @@ midori_bookmarks_edit_clicked_cb (GtkWidget* toolitem,
{
KatzeItem* item;
MidoriBrowser* browser;
gint64 parentid;
gtk_tree_model_get (model, &iter, 0, &item, -1);
g_assert (!KATZE_ITEM_IS_SEPARATOR (item));
browser = midori_browser_get_for_widget (bookmarks->treeview);
parentid = katze_item_get_meta_integer (item, "parentid");
midori_browser_edit_bookmark_dialog_new (
browser, item, FALSE, KATZE_ITEM_IS_FOLDER (item), NULL);
if (katze_item_get_meta_integer (item, "parentid") != parentid)
{
gtk_tree_store_clear (GTK_TREE_STORE (model));
midori_bookmarks_read_from_db_to_model (bookmarks, GTK_TREE_STORE (model),
NULL, 0, NULL);
}
g_object_unref (item);
}
}
@ -382,6 +441,47 @@ midori_bookmarks_toolbar_update (MidoriBookmarks *bookmarks)
gtk_widget_set_sensitive (GTK_WIDGET (bookmarks->edit), selected);
}
gboolean
midori_bookmarks_update_item_db (sqlite3* db,
KatzeItem* item)
{
gchar* sqlcmd;
char* errmsg = NULL;
gchar* parentid;
gboolean updated;
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 = %" G_GINT64_FORMAT ";",
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"),
katze_item_get_meta_integer (item, "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);
return updated;
}
static void
midori_bookmarks_delete_clicked_cb (GtkWidget* toolitem,
MidoriBookmarks* bookmarks)
@ -496,8 +596,8 @@ midori_bookmarks_set_app (MidoriBookmarks* bookmarks,
g_object_ref (app);
bookmarks->array = katze_object_get_object (app, "bookmarks");
midori_bookmarks_read_from_db_to_model (bookmarks, GTK_TREE_STORE (model), NULL, "", NULL);
g_signal_connect (bookmarks->array, "add-item",
midori_bookmarks_read_from_db_to_model (bookmarks, GTK_TREE_STORE (model), NULL, 0, NULL);
g_signal_connect_after (bookmarks->array, "add-item",
G_CALLBACK (midori_bookmarks_add_item_cb), bookmarks);
g_signal_connect (bookmarks->array, "remove-item",
G_CALLBACK (midori_bookmarks_remove_item_cb), bookmarks);
@ -687,7 +787,9 @@ midori_bookmarks_open_in_tab_activate_cb (GtkWidget* menuitem,
KatzeItem* child;
KatzeArray* array;
array = midori_bookmarks_read_from_db (bookmarks, katze_item_get_name (item), NULL);
array = midori_bookmarks_read_from_db (bookmarks,
katze_item_get_meta_integer (item, "parentid"), NULL);
g_return_if_fail (KATZE_IS_ARRAY (array));
KATZE_ARRAY_FOREACH_ITEM (child, array)
{
@ -843,7 +945,7 @@ midori_bookmarks_row_expanded_cb (GtkTreeView* treeview,
model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
gtk_tree_model_get (model, iter, 0, &item, -1);
midori_bookmarks_read_from_db_to_model (bookmarks, GTK_TREE_STORE (model),
iter, katze_item_get_name (item), NULL);
iter, katze_item_get_meta_integer (item, "id"), NULL);
g_object_unref (item);
}
@ -885,7 +987,7 @@ midori_bookmarks_filter_timeout_cb (gpointer data)
gtk_tree_store_clear (treestore);
midori_bookmarks_read_from_db_to_model (bookmarks,
treestore, NULL, NULL, bookmarks->filter);
treestore, NULL, 0, bookmarks->filter);
return FALSE;
}

View File

@ -40,15 +40,19 @@ midori_bookmarks_get_type (void);
GtkWidget*
midori_bookmarks_new (void);
void
midori_bookmarks_insert_item_db (sqlite3* db,
KatzeItem* item,
const gchar* folder);
gint64
midori_bookmarks_insert_item_db (sqlite3* db,
KatzeItem* item,
gint64 parentid);
void
midori_bookmarks_import_array_db (sqlite3* db,
KatzeArray* array,
const gchar* folder);
midori_bookmarks_import_array_db (sqlite3* db,
KatzeArray* array,
gint64 parentid);
gboolean
midori_bookmarks_update_item_db (sqlite3* db,
KatzeItem* item);
G_END_DECLS

View File

@ -268,7 +268,7 @@ def configure (conf):
if check_version (conf.env['LIBSOUP_VERSION'], 2, 37, 1):
conf.define ('HAVE_LIBSOUP_2_37_1', 1)
check_pkg ('libxml-2.0', '2.6')
check_pkg ('sqlite3', '3.0', True, var='SQLITE')
check_pkg ('sqlite3', '3.6.19', True, var='SQLITE')
if option_enabled ('hildon'):
if check_pkg ('hildon-1', mandatory=False, var='HILDON'):