From: Alexander Butenko Date: Tue, 2 Feb 2010 20:10:03 +0000 (+0100) Subject: Re-implement history panel based on sqlite queries X-Git-Url: https://spindle.queued.net/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3848becaa6e3617bde2c8f0387a40c414d422b91;p=midori Re-implement history panel based on sqlite queries --- diff --git a/panels/midori-history.c b/panels/midori-history.c index b198e7a6..ba63067d 100644 --- a/panels/midori-history.c +++ b/panels/midori-history.c @@ -31,6 +31,12 @@ midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser, gboolean new_bookmark, gboolean is_folder); +#include "config.h" + +#if HAVE_SQLITE + #include +#endif + struct _MidoriHistory { GtkVBox parent_instance; @@ -114,6 +120,144 @@ midori_history_get_stock_id (MidoriViewable* viewable) return STOCK_HISTORY; } +#if HAVE_SQLITE +static void +midori_history_clear_db (MidoriHistory* history) +{ + gchar* sqlcmd; + sqlite3* db; + char* errmsg = NULL; + + db = g_object_get_data (G_OBJECT (history->array), "db"); + sqlcmd = sqlite3_mprintf ("DELETE FROM history"); + + if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) != SQLITE_OK) + { + g_printerr (_("Failed to remove history item: %s\n"), errmsg); + sqlite3_free (errmsg); + } + + sqlite3_free (sqlcmd); +} + +static void +midori_history_remove_item_from_db (MidoriHistory* history, + KatzeItem* item, + int age) +{ + gchar* sqlcmd; + sqlite3* db; + char* errmsg = NULL; + + db = g_object_get_data (G_OBJECT (history->array), "db"); + + if (katze_item_get_uri (item)) + sqlcmd = sqlite3_mprintf ( + "DELETE FROM history WHERE uri = '%q' AND" + " title = '%q' AND date = %llu", + katze_item_get_uri (item), + katze_item_get_name (item), + katze_item_get_added (item)); + else + sqlcmd = sqlite3_mprintf ( + "DELETE FROM history WHERE day = %d", katze_item_get_added (item)); + + if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) != SQLITE_OK) + { + g_printerr (_("Failed to remove history item: %s\n"), errmsg); + sqlite3_free (errmsg); + } + + sqlite3_free (sqlcmd); +} + +static gboolean +midori_history_read_from_db (MidoriHistory* history, + GtkTreeModel* model, + GtkTreeIter* parent, + int req_day) +{ + sqlite3* db; + sqlite3_stmt* statement; + gint result; + gchar* sqlcmd; + + GtkTreeIter iter; + GtkTreeIter root_iter; + + db = g_object_get_data (G_OBJECT (history->array), "db"); + + if (req_day == 0) + sqlcmd = g_strdup ("SELECT day, date, " + "(strftime ('%s','now') - date) / 86400 as age " + " FROM history GROUP BY day ORDER BY day ASC"); + else + sqlcmd = g_strdup_printf ("SELECT uri, title, date, day " + " FROM history WHERE day = '%d' " + " GROUP BY uri ORDER BY date ASC", req_day); + + if (sqlite3_prepare_v2 (db, sqlcmd, -1, &statement, NULL) != SQLITE_OK) + { + g_free (sqlcmd); + return FALSE; + } + g_free (sqlcmd); + + while ((result = sqlite3_step (statement)) == SQLITE_ROW) + { + KatzeItem* item; + const unsigned char* uri; + const unsigned char* title; + sqlite3_int64 date; + sqlite3_int64 day; + sqlite3_int64 age; + gchar token[50]; + + if (req_day == 0) + { + day = sqlite3_column_int64 (statement, 0); + date = sqlite3_column_int64 (statement, 1); + age = sqlite3_column_int64 (statement, 2); + + item = katze_item_new (); + katze_item_set_added (item, day); + strftime (token, sizeof (token), "%x", localtime ((time_t *)&date)); + katze_item_set_name (item, token); + gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &root_iter, NULL, + 0, 0, item, 1, age, -1); + /* FIXME: Always show expanders even if no child nodes? */ + gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter, &root_iter, + 0, 0, item, 1, -1, -1); + } + else + { + uri = sqlite3_column_text (statement, 0); + title = sqlite3_column_text (statement, 1); + date = sqlite3_column_int64 (statement, 2); + day = sqlite3_column_int64 (statement, 3); + if (!uri) + continue; + + item = katze_item_new (); + katze_item_set_added (item, date); + katze_item_set_uri (item, (gchar*)uri); + katze_item_set_name (item, (gchar*)title); + /* FIXME: Gtk-WARNING **: gtk/gtktreestore.c:946: Invalid column + number -1076101456 added to iter (remember to end your list + of columns with a -1) */ + gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), NULL, parent, + 0, 0, item, 1, -1, -1); + } + } + + if (result != SQLITE_DONE) + g_print (_("Failed to execute database statement: %s\n"), + sqlite3_errmsg (db)); + + sqlite3_finalize (statement); + return FALSE; +} + static void midori_history_add_clicked_cb (GtkWidget* toolitem) { @@ -133,16 +277,11 @@ midori_history_delete_clicked_cb (GtkWidget* toolitem, &model, &iter)) { KatzeItem* item; - KatzeArray* parent; - - gtk_tree_model_get (model, &iter, 0, &item, -1); - - /* FIXME: Even toplevel items should technically have a parent */ - g_return_if_fail (katze_item_get_parent (item)); - - parent = katze_item_get_parent (item); - katze_array_remove_item (parent, item); + gint64 age; + gtk_tree_model_get (model, &iter, 0, &item, 1, &age, -1); + midori_history_remove_item_from_db (history, item, age); + gtk_tree_store_remove (GTK_TREE_STORE (model), &iter); g_object_unref (item); } } @@ -165,7 +304,7 @@ midori_history_clear_clicked_cb (GtkWidget* toolitem, if (result != GTK_RESPONSE_YES) return; - katze_array_clear (history->array); + midori_history_clear_db (history); } static void @@ -197,6 +336,7 @@ midori_history_cursor_or_row_changed_cb (GtkTreeView* treeview, gtk_widget_set_sensitive (history->delete, FALSE); } } +#endif static GtkWidget* midori_history_get_toolbar (MidoriViewable* viewable) @@ -206,12 +346,15 @@ midori_history_get_toolbar (MidoriViewable* viewable) if (!history->toolbar) { GtkWidget* toolbar; + #if HAVE_SQLITE GtkToolItem* toolitem; + #endif toolbar = gtk_toolbar_new (); gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH_HORIZ); gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON); history->toolbar = toolbar; + #if HAVE_SQLITE toolitem = gtk_tool_button_new_from_stock (STOCK_BOOKMARK_ADD); gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem), _("Bookmark the selected history item")); @@ -245,6 +388,7 @@ midori_history_get_toolbar (MidoriViewable* viewable) G_CALLBACK (gtk_widget_destroyed), &history->delete); g_signal_connect (history->clear, "destroy", G_CALLBACK (gtk_widget_destroyed), &history->clear); + #endif } return history->toolbar; @@ -258,222 +402,6 @@ midori_history_viewable_iface_init (MidoriViewableIface* iface) iface->get_toolbar = midori_history_get_toolbar; } -static void -midori_history_add_item_cb (KatzeArray* array, - KatzeItem* added_item, - MidoriHistory* history); - -static void -midori_history_remove_item_cb (KatzeArray* array, - KatzeItem* removed_item, - MidoriHistory* history); - -static void -midori_history_clear_cb (KatzeArray* array, - MidoriHistory* history); - -static void -midori_history_disconnect_folder (MidoriHistory* history, - KatzeArray* array, - gboolean unref) -{ - KatzeItem* item; - guint i; - - g_return_if_fail (KATZE_IS_ARRAY (array)); - - g_signal_handlers_disconnect_by_func (array, - midori_history_add_item_cb, history); - g_signal_handlers_disconnect_by_func (array, - midori_history_remove_item_cb, history); - g_signal_handlers_disconnect_by_func (array, - midori_history_clear_cb, history); - - i = 0; - while ((item = katze_array_get_nth_item (array, i++))) - { - if (KATZE_IS_ARRAY (item)) - midori_history_disconnect_folder (history, KATZE_ARRAY (item), unref); - if (unref) - g_object_unref (item); - } -} - -static void -midori_history_add_item_cb (KatzeArray* array, - KatzeItem* added_item, - MidoriHistory* history) -{ - GtkTreeModel* model; - GtkTreeIter iter; - guint i; - - g_return_if_fail (KATZE_IS_ARRAY (array)); - g_return_if_fail (KATZE_IS_ITEM (added_item)); - g_return_if_fail (MIDORI_IS_HISTORY (history)); - - if (KATZE_IS_ARRAY (added_item)) - { - g_signal_connect (added_item, "add-item", - G_CALLBACK (midori_history_add_item_cb), history); - g_signal_connect (added_item, "remove-item", - G_CALLBACK (midori_history_remove_item_cb), history); - g_signal_connect (added_item, "clear", - G_CALLBACK (midori_history_clear_cb), history); - } - - g_object_ref (added_item); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (history->treeview)); - - if (array == history->array) - { - gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), - &iter, NULL, 0, 0, added_item, -1); - return; - } - - i = 0; - /* FIXME: Recurse over children of folders, too */ - while (gtk_tree_model_iter_nth_child (model, &iter, NULL, i)) - { - KatzeItem* item; - - gtk_tree_model_get (model, &iter, 0, &item, -1); - if (item == (KatzeItem*)array) - { - GtkTreeIter child_iter; - - gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), - &child_iter, &iter, 0, 0, added_item, -1); - break; - } - g_object_unref (item); - - i++; - } -} - -static void -midori_history_remove_iter (GtkTreeModel* model, - GtkTreeIter* parent, - KatzeItem* removed_item) -{ - guint i; - GtkTreeIter iter; - - i = 0; - while (gtk_tree_model_iter_nth_child (model, &iter, parent, i)) - { - KatzeItem* item; - - gtk_tree_model_get (model, &iter, 0, &item, -1); - - if (item == removed_item) - { - gtk_tree_store_remove (GTK_TREE_STORE (model), &iter); - g_object_unref (item); - break; - } - - if (KATZE_IS_ARRAY (item)) - midori_history_remove_iter (model, &iter, removed_item); - - g_object_unref (item); - i++; - } -} - -static void -midori_history_remove_item_cb (KatzeArray* array, - KatzeItem* removed_item, - MidoriHistory* history) -{ - GtkTreeModel* model; - - g_assert (KATZE_IS_ARRAY (array)); - g_assert (KATZE_IS_ITEM (removed_item)); - - if (KATZE_IS_ARRAY (removed_item)) - midori_history_disconnect_folder (history, KATZE_ARRAY (removed_item), TRUE); - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (history->treeview)); - midori_history_remove_iter (model, NULL, removed_item); - g_object_unref (removed_item); -} - -static void -midori_history_clear_cb (KatzeArray* array, - MidoriHistory* history) -{ - GtkTreeView* treeview; - GtkTreeStore* store; - - g_assert (KATZE_IS_ARRAY (array)); - - if (array == history->array) - { - treeview = GTK_TREE_VIEW (history->treeview); - store = GTK_TREE_STORE (gtk_tree_view_get_model (treeview)); - gtk_tree_store_clear (store); - } - else - { - KatzeItem* item; - guint i; - - i = 0; - while ((item = katze_array_get_nth_item (array, i++))) - midori_history_remove_item_cb (array, item, history); - } - - midori_history_disconnect_folder (history, array, TRUE); -} - -static void -midori_history_insert_item (MidoriHistory* history, - GtkTreeStore* treestore, - GtkTreeIter* parent, - KatzeItem* item, - gint64 day) -{ - GtkTreeIter iter; - gint64 age = -1; - - g_return_if_fail (KATZE_IS_ITEM (item)); - - if (KATZE_IS_ARRAY (item)) - { - GtkTreeIter* piter; - gint64 pday; - guint i; - KatzeItem* child; - - g_signal_connect (item, "add-item", - G_CALLBACK (midori_history_add_item_cb), history); - g_signal_connect (item, "remove-item", - G_CALLBACK (midori_history_remove_item_cb), history); - g_signal_connect (item, "clear", - G_CALLBACK (midori_history_clear_cb), history); - - piter = parent; - if ((pday = katze_item_get_added (item))) - { - age = day - pday; - gtk_tree_store_insert_with_values (treestore, &iter, parent, - 0, 0, item, 1, age, -1); - piter = &iter; - } - i = 0; - while ((child = katze_array_get_nth_item (KATZE_ARRAY (item), i++))) - midori_history_insert_item (history, treestore, piter, child, day); - } - else - { - gtk_tree_store_insert_with_values (treestore, &iter, parent, - 0, 0, item, 1, age, -1); - } -} - static void midori_history_set_app (MidoriHistory* history, MidoriApp* app) @@ -482,26 +410,21 @@ midori_history_set_app (MidoriHistory* history, if (history->array) { - midori_history_disconnect_folder (history, history->array, TRUE); g_object_unref (history->array); model = gtk_tree_view_get_model (GTK_TREE_VIEW (history->treeview)); gtk_tree_store_clear (GTK_TREE_STORE (model)); } + katze_assign (history->app, app); if (!app) return; - g_object_ref (app); - history->array = katze_object_get_object (app, "history"); - if (history->array) - { - time_t now = time (NULL); - gint64 day = sokoke_time_t_to_julian (&now); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (history->treeview)); - midori_history_insert_item (history, GTK_TREE_STORE (model), - NULL, KATZE_ITEM (history->array), day); - } + history->array = katze_object_get_object (app, "history"); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (history->treeview)); + #if HAVE_SQLITE + midori_history_read_from_db (history, model, NULL, 0); + #endif } static void @@ -550,17 +473,16 @@ midori_history_treeview_render_icon_cb (GtkTreeViewColumn* column, GtkWidget* treeview) { KatzeItem* item; + gint64 age; GdkPixbuf* pixbuf = NULL; - gtk_tree_model_get (model, iter, 0, &item, -1); - - g_assert (KATZE_IS_ITEM (item)); + gtk_tree_model_get (model, iter, 0, &item, 1, &age, -1); - if (KATZE_IS_ARRAY (item)) + if (katze_item_get_uri (item)) + pixbuf = katze_load_cached_icon (katze_item_get_uri (item), treeview); + else pixbuf = gtk_widget_render_icon (treeview, GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL); - else - pixbuf = katze_load_cached_icon (katze_item_get_uri (item), treeview); g_object_set (renderer, "pixbuf", pixbuf, NULL); @@ -582,9 +504,7 @@ midori_history_treeview_render_text_cb (GtkTreeViewColumn* column, gtk_tree_model_get (model, iter, 0, &item, 1, &age, -1); - g_assert (KATZE_IS_ITEM (item)); - - if (KATZE_IS_ARRAY (item)) + if (age != -1) { gchar* sdate; @@ -633,6 +553,7 @@ midori_history_treeview_render_text_cb (GtkTreeViewColumn* column, g_object_unref (item); } +#if HAVE_SQLITE static void midori_history_row_activated_cb (GtkTreeView* treeview, GtkTreePath* path, @@ -791,22 +712,6 @@ midori_history_bookmark_activate_cb (GtkWidget* menuitem, } } -static void -midori_history_delete_activate_cb (GtkWidget* menuitem, - MidoriHistory* history) -{ - KatzeItem* item; - KatzeArray* parent; - - item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem"); - - /* FIXME: Even toplevel items should technically have a parent */ - g_return_if_fail (katze_item_get_parent (item)); - - parent = katze_item_get_parent (item); - katze_array_remove_item (parent, item); -} - static void midori_history_popup (GtkWidget* widget, GdkEventButton* event, @@ -836,7 +741,7 @@ midori_history_popup (GtkWidget* widget, gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_widget_show (menuitem); midori_history_popup_item (menu, GTK_STOCK_DELETE, NULL, - item, midori_history_delete_activate_cb, history); + item, midori_history_delete_clicked_cb, history); katze_widget_popup (widget, GTK_MENU (menu), event, KATZE_MENU_POSITION_CURSOR); } @@ -924,6 +829,33 @@ midori_history_popup_menu_cb (GtkWidget* widget, } } +static void +midori_history_row_expanded_cb (GtkTreeView* treeview, + GtkTreeIter* iter, + GtkTreePath* path, + MidoriHistory* history) +{ + GtkTreeModel* model; + KatzeItem* item; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)); + gtk_tree_model_get (model, iter, 0, &item, -1); + /* FIXME: We need always repopulate parent. Now ignoring dupes */ + if (gtk_tree_model_iter_n_children (model, iter) < 2) + midori_history_read_from_db (history, model, iter, katze_item_get_added (item)); + g_object_unref (item); +} + +static void +midori_history_row_collapsed_cb (GtkTreeView *treeview, + GtkTreeIter *iter, + GtkTreePath *path, + gpointer user_data) +{ + /* FIXME: Free parent childs on close and repopulate them again on open */ +} +#endif + static void midori_history_init (MidoriHistory* history) { @@ -953,6 +885,7 @@ midori_history_init (MidoriHistory* history) history, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_object_unref (model); + #if HAVE_SQLITE g_object_connect (treeview, "signal::row-activated", midori_history_row_activated_cb, history, @@ -964,12 +897,18 @@ midori_history_init (MidoriHistory* history) midori_history_button_release_event_cb, history, "signal::key-release-event", midori_history_key_release_event_cb, history, + "signal::row-expanded", + midori_history_row_expanded_cb, history, + "signal::row-collapsed", + midori_history_row_collapsed_cb, history, "signal::popup-menu", midori_history_popup_menu_cb, history, NULL); + #endif gtk_widget_show (treeview); gtk_box_pack_start (GTK_BOX (history), treeview, TRUE, TRUE, 0); history->treeview = treeview; + /* FIXME: We need to connect a signal here, to add new pages into history */ } static void @@ -982,7 +921,6 @@ midori_history_finalize (GObject* object) /* FIXME: We don't unref items (last argument is FALSE) because our reference counting is incorrect. */ - midori_history_disconnect_folder (history, history->array, FALSE); g_object_unref (history->array); }