]> spindle.queued.net Git - midori/commitdiff
Refactor History panel into a separate class
authorChristian Dywan <christian@twotoasts.de>
Sat, 21 Feb 2009 22:59:02 +0000 (23:59 +0100)
committerChristian Dywan <christian@twotoasts.de>
Sat, 21 Feb 2009 22:59:02 +0000 (23:59 +0100)
This brings back the problem of address and title of items
showing up in the history unfortunately.

Now the history items are appended rather than prepended,
we probably want to fix that in the future.

midori/main.c
midori/midori-browser.c
panels/midori-history.c [new file with mode: 0644]
panels/midori-history.h [new file with mode: 0644]
po/POTFILES.in

index 8095064227017c52ac7d9984771e04e917c5eb38..7306628d96e51563b980af5c01d313130ed92b77 100644 (file)
@@ -21,6 +21,7 @@
 #include "midori-console.h"
 #include "midori-extension.h"
 #include "midori-extensions.h"
+#include "midori-history.h"
 #include "midori-panel.h"
 #include "midori-preferences.h"
 #include "midori-plugins.h"
@@ -1210,6 +1211,11 @@ midori_app_add_browser_cb (MidoriApp*     app,
     gtk_widget_show (addon);
     midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
 
+    /* History */
+    addon = g_object_new (MIDORI_TYPE_HISTORY, "app", app, NULL);
+    gtk_widget_show (addon);
+    midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
+
     /* Transfers */
     #if 0
     addon = midori_view_new (net);
index 0d2bd91998bbdfb97dbb93ecaff4d1b298107ff3..c5c228b6c46f0ff0721cf7f955f08cc171a33d55 100644 (file)
@@ -53,7 +53,6 @@ struct _MidoriBrowser
     GtkWidget* bookmarkbar;
 
     GtkWidget* panel;
-    GtkWidget* panel_history;
     GtkWidget* notebook;
 
     GtkWidget* inspector;
@@ -462,19 +461,20 @@ midori_view_notify_title_cb (GtkWidget*     view,
         KatzeItem* item;
         KatzeItem* proxy;
 
-        if (!browser->history)
-            return;
-
-        item = g_object_get_data (G_OBJECT (view), "history-item-added");
-        proxy = midori_view_get_proxy_item (MIDORI_VIEW (view));
-        if (item && katze_item_get_added (item) == katze_item_get_added (proxy))
-            katze_item_set_name (item, katze_item_get_name (proxy));
-        else
+        if (browser->history &&
+            katze_object_get_boolean (browser->settings, "remember-last-visited-pages"))
         {
-            katze_object_assign (item, katze_item_copy (proxy));
-            midori_browser_new_history_item (browser, g_object_ref (item));
-            g_object_set_data_full (G_OBJECT (view), "history-item-added",
-                                    item, (GDestroyNotify)g_object_unref);
+            item = g_object_get_data (G_OBJECT (view), "history-item-added");
+            proxy = midori_view_get_proxy_item (MIDORI_VIEW (view));
+            if (item && katze_item_get_added (item) == katze_item_get_added (proxy))
+                katze_item_set_name (item, katze_item_get_name (proxy));
+            else
+            {
+                katze_object_assign (item, katze_item_copy (proxy));
+                midori_browser_new_history_item (browser, g_object_ref (item));
+                g_object_set_data_full (G_OBJECT (view), "history-item-added",
+                                        item, (GDestroyNotify)g_object_unref);
+            }
         }
     }
 
@@ -2412,20 +2412,6 @@ midori_browser_bookmark_open_in_window_activate_cb (GtkWidget*     menuitem,
         g_signal_emit (browser, signals[NEW_WINDOW], 0, uri);
 }
 
-static void
-midori_browser_bookmark_bookmark_activate_cb (GtkWidget*     menuitem,
-                                              MidoriBrowser* browser)
-{
-    KatzeItem* item;
-    const gchar* uri;
-
-    item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
-    uri = katze_item_get_uri (item);
-
-    if (uri && *uri)
-        midori_browser_edit_bookmark_dialog_new (browser, item, TRUE);
-}
-
 static void
 midori_browser_bookmark_edit_activate_cb (GtkWidget*     menuitem,
                                           MidoriBrowser* browser)
@@ -2440,62 +2426,6 @@ midori_browser_bookmark_edit_activate_cb (GtkWidget*     menuitem,
         midori_browser_edit_bookmark_dialog_new (browser, item, FALSE);
 }
 
-static void
-midori_browser_model_remove_item (GtkTreeModel* model,
-                                  KatzeItem*    item,
-                                  GtkTreeIter*  iter)
-{
-    GtkTreeIter child_iter;
-    KatzeItem* child;
-    KatzeArray* parent;
-    gint i, n;
-
-    if (KATZE_IS_ARRAY (item))
-    {
-        n = katze_array_get_length (KATZE_ARRAY (item));
-        for (i = 0; i < n; i++)
-        {
-            child = katze_array_get_nth_item (KATZE_ARRAY (item), 0);
-            katze_array_remove_item (KATZE_ARRAY (item), child);
-        }
-        while (gtk_tree_model_iter_nth_child (model, &child_iter, iter, 0))
-            gtk_tree_store_remove (GTK_TREE_STORE (model), &child_iter);
-    }
-
-    gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
-    g_object_unref (item);
-
-    parent = katze_item_get_parent (item);
-    katze_array_remove_item (parent, item);
-}
-
-static void
-midori_browser_history_delete (MidoriBrowser* browser)
-{
-    GtkTreeView* treeview;
-    GtkTreeModel* model;
-    GtkTreeIter iter;
-    KatzeItem* item;
-    GtkAction* location_action;
-
-    treeview = GTK_TREE_VIEW (browser->panel_history);
-    if (katze_tree_view_get_selected_iter (treeview, &model, &iter))
-    {
-        location_action = _action_by_name (browser, "Location");
-        gtk_tree_model_get (model, &iter, 0, &item, -1);
-        midori_browser_model_remove_item (model, item, &iter);
-        midori_location_action_delete_item_from_uri (
-            MIDORI_LOCATION_ACTION (location_action), katze_item_get_uri (item));
-    }
-}
-
-static void
-midori_browser_history_delete_activate_cb (GtkWidget*     menuitem,
-                                           MidoriBrowser* browser)
-{
-    midori_browser_history_delete (browser);
-}
-
 static void
 midori_browser_bookmark_delete_activate_cb (GtkWidget*     menuitem,
                                             MidoriBrowser* browser)
@@ -2518,7 +2448,6 @@ static void
 midori_browser_bookmark_popup (GtkWidget*      widget,
                                GdkEventButton* event,
                                KatzeItem*      item,
-                               gboolean        history_item,
                                MidoriBrowser*  browser)
 {
     GtkWidget* menu;
@@ -2531,162 +2460,18 @@ midori_browser_bookmark_popup (GtkWidget*      widget,
         item, midori_browser_bookmark_open_in_tab_activate_cb, browser);
     midori_browser_bookmark_popup_item (menu, STOCK_WINDOW_NEW, _("Open in New _Window"),
         item, midori_browser_bookmark_open_in_window_activate_cb, browser);
-    if (history_item && !KATZE_IS_ARRAY (item))
-        midori_browser_bookmark_popup_item (menu, STOCK_BOOKMARK_ADD, NULL,
-            item, midori_browser_bookmark_bookmark_activate_cb, browser);
     menuitem = gtk_separator_menu_item_new ();
     gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
     gtk_widget_show (menuitem);
-    if (!history_item)
-    {
-        midori_browser_bookmark_popup_item (menu, GTK_STOCK_EDIT, NULL,
-            item, midori_browser_bookmark_edit_activate_cb, browser);
-        midori_browser_bookmark_popup_item (menu, GTK_STOCK_DELETE, NULL,
-            item, midori_browser_bookmark_delete_activate_cb, browser);
-    }
-    else
-        midori_browser_bookmark_popup_item (menu, GTK_STOCK_DELETE, NULL,
-            item, midori_browser_history_delete_activate_cb, browser);
+    midori_browser_bookmark_popup_item (menu, GTK_STOCK_EDIT, NULL,
+        item, midori_browser_bookmark_edit_activate_cb, browser);
+    midori_browser_bookmark_popup_item (menu, GTK_STOCK_DELETE, NULL,
+        item, midori_browser_bookmark_delete_activate_cb, browser);
 
     sokoke_widget_popup (widget, GTK_MENU (menu),
                          event, SOKOKE_MENU_POSITION_CURSOR);
 }
 
-static void
-midori_panel_history_row_activated_cb (GtkTreeView*       treeview,
-                                       GtkTreePath*       path,
-                                       GtkTreeViewColumn* column,
-                                       MidoriBrowser*     browser)
-{
-    KatzeItem* item;
-    GtkTreeModel* model;
-    GtkTreeIter iter;
-    const gchar* uri;
-
-    model = gtk_tree_view_get_model (treeview);
-    if (gtk_tree_model_get_iter (model, &iter, path))
-    {
-        gtk_tree_model_get (model, &iter, 0, &item, -1);
-        if (KATZE_IS_ITEM (item))
-        {
-            uri = katze_item_get_uri (item);
-            midori_browser_set_current_uri (browser, uri);
-        }
-        g_object_unref (item);
-    }
-}
-
-static void
-midori_panel_history_cursor_or_row_changed_cb (GtkTreeView*   tree_view,
-                                               MidoriBrowser* browser)
-{
-    GtkTreeModel* model;
-    GtkTreeIter iter;
-    KatzeItem* item;
-    gboolean is_page;
-
-    if (katze_tree_view_get_selected_iter (tree_view, &model, &iter))
-    {
-        gtk_tree_model_get (model, &iter, 0, &item, -1);
-
-        is_page = !KATZE_IS_ARRAY (item) && katze_item_get_uri (item);
-        _action_set_sensitive (browser, "HistoryAddBookmark", is_page);
-    }
-    else
-    {
-        _action_set_sensitive (browser, "HistoryAddBookmark", FALSE);
-    }
-}
-
-static void
-_midori_panel_history_popup (GtkWidget*      widget,
-                             GdkEventButton* event,
-                             KatzeItem*      item,
-                             MidoriBrowser*  browser)
-{
-    midori_browser_bookmark_popup (widget, event, item, TRUE, browser);
-}
-
-static gboolean
-midori_panel_history_button_release_event_cb (GtkWidget*      widget,
-                                              GdkEventButton* event,
-                                              MidoriBrowser*  browser)
-{
-    GtkTreeModel* model;
-    GtkTreeIter iter;
-    KatzeItem* item;
-    const gchar* uri;
-    gint n;
-
-    if (event->button != 2 && event->button != 3)
-        return FALSE;
-
-    if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget),
-                                            &model, &iter))
-    {
-        gtk_tree_model_get (model, &iter, 0, &item, -1);
-        uri = katze_item_get_uri (item);
-        if (event->button == 2)
-        {
-            if (uri && *uri)
-            {
-                n = midori_browser_add_uri (browser, uri);
-                midori_browser_set_current_page (browser, n);
-            }
-        }
-        else
-            _midori_panel_history_popup (widget, event, item, browser);
-
-        g_object_unref (item);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-static gboolean
-midori_panel_history_key_release_event_cb (GtkWidget*     widget,
-                                           GdkEventKey*   event,
-                                           MidoriBrowser* browser)
-{
-    GtkTreeView* treeview;
-    GtkTreeModel* model;
-    GtkTreeIter iter;
-    KatzeItem* item;
-    GtkAction* location_action;
-
-    if (event->keyval != GDK_Delete)
-        return FALSE;
-
-    treeview = GTK_TREE_VIEW (widget);
-    if (katze_tree_view_get_selected_iter (treeview, &model, &iter))
-    {
-        location_action = _action_by_name (browser, "Location");
-        gtk_tree_model_get (model, &iter, 0, &item, -1);
-        midori_location_action_delete_item_from_uri (
-            MIDORI_LOCATION_ACTION (location_action), katze_item_get_uri (item));
-        midori_browser_model_remove_item (model, item, &iter);
-    }
-
-    return FALSE;
-}
-
-static void
-midori_panel_history_popup_menu_cb (GtkWidget*     widget,
-                                    MidoriBrowser* browser)
-{
-    GtkTreeModel* model;
-    GtkTreeIter iter;
-    KatzeItem* item;
-
-    if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget),
-                                            &model, &iter))
-    {
-        gtk_tree_model_get (model, &iter, 0, &item, -1);
-        _midori_panel_history_popup (widget, NULL, item, browser);
-        g_object_unref (item);
-    }
-}
-
 static void
 midori_browser_menu_bookmarks_item_activate_cb (GtkWidget*     widget,
                                                 MidoriBrowser* browser)
@@ -2723,7 +2508,7 @@ midori_browser_bookmarkbar_item_button_press_event_cb (GtkWidget*      toolitem,
     else if (event->button == 3)
     {
         item = (KatzeItem*)g_object_get_data (G_OBJECT (toolitem), "KatzeItem");
-        midori_browser_bookmark_popup (toolitem, NULL, item, FALSE, browser);
+        midori_browser_bookmark_popup (toolitem, NULL, item, browser);
         return TRUE;
     }
     return FALSE;
@@ -2736,86 +2521,6 @@ _action_bookmark_add_activate (GtkAction*     action,
     midori_browser_edit_bookmark_dialog_new (browser, NULL, TRUE);
 }
 
-static void
-midori_browser_history_render_icon_cb (GtkTreeViewColumn* column,
-                                       GtkCellRenderer*   renderer,
-                                       GtkTreeModel*      model,
-                                       GtkTreeIter*       iter,
-                                       GtkWidget*         treeview)
-{
-    KatzeItem* item;
-    GdkPixbuf* pixbuf = NULL;
-
-    gtk_tree_model_get (model, iter, 0, &item, -1);
-
-    g_assert (KATZE_IS_ITEM (item));
-
-    if (KATZE_IS_ARRAY (item))
-        pixbuf = gtk_widget_render_icon (treeview, GTK_STOCK_DIRECTORY,
-                                         GTK_ICON_SIZE_MENU, NULL);
-    else
-        pixbuf = katze_net_load_icon (
-            MIDORI_BROWSER (gtk_widget_get_toplevel (treeview))->net,
-            katze_item_get_uri (item), NULL, treeview, NULL);
-
-    g_object_set (renderer, "pixbuf", pixbuf, NULL);
-
-    if (pixbuf)
-        g_object_unref (pixbuf);
-
-    g_object_unref (item);
-}
-
-static void
-midori_browser_history_render_text_cb (GtkTreeViewColumn* column,
-                                       GtkCellRenderer*   renderer,
-                                       GtkTreeModel*      model,
-                                       GtkTreeIter*       iter,
-                                       GtkWidget*         treeview)
-{
-    KatzeItem* item;
-    char* sdate;
-    gint64 age;
-
-    gtk_tree_model_get (model, iter, 0, &item, 1, &age, -1);
-
-    g_assert (KATZE_IS_ITEM (item));
-
-    if (KATZE_IS_ARRAY (item))
-    {
-        g_assert (age >= 0);
-
-        if (age > 7)
-        {
-            g_object_set (renderer, "text", katze_item_get_token (item), NULL);
-        }
-        else if (age > 6)
-        {
-            sdate = g_strdup_printf (_("A week ago"));
-            g_object_set (renderer, "text", sdate, NULL);
-            g_free (sdate);
-        }
-        else if (age > 1)
-        {
-            sdate = g_strdup_printf (_("%d days ago"), (gint)age);
-            g_object_set (renderer, "text", sdate, NULL);
-            g_free (sdate);
-        }
-        else
-        {
-            if (age == 0)
-                sdate = _("Today");
-            else
-                sdate = _("Yesterday");
-            g_object_set (renderer, "text", sdate, NULL);
-        }
-    }
-    else
-        g_object_set (renderer, "text", katze_item_get_name (item), NULL);
-
-    g_object_unref (item);
-}
-
 static void
 _action_manage_search_engines_activate (GtkAction*     action,
                                         MidoriBrowser* browser)
@@ -3027,54 +2732,6 @@ gtk_notebook_button_press_event_cb (GtkNotebook*    notebook,
     return FALSE;
 }
 
-static void
-_action_history_delete_activate (GtkAction*     action,
-                                 MidoriBrowser* browser)
-{
-    midori_browser_history_delete (browser);
-}
-
-static void
-_action_history_clear_activate (GtkAction*     action,
-                                MidoriBrowser* browser)
-{
-    GtkWidget* dialog;
-    gint result;
-
-    if (!browser->history)
-        return;
-
-    dialog = gtk_message_dialog_new (GTK_WINDOW (browser),
-        GTK_DIALOG_DESTROY_WITH_PARENT,
-        GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
-        _("Are you sure you want to remove all history items?"));
-    result = gtk_dialog_run (GTK_DIALOG (dialog));
-    gtk_widget_destroy (dialog);
-    if (result != GTK_RESPONSE_YES)
-        return;
-
-    katze_array_clear (browser->history);
-}
-
-static void
-_action_history_add_bookmark_activate (GtkAction*     action,
-                                       MidoriBrowser* browser)
-{
-    GtkTreeView* tree_view;
-    GtkTreeModel* model;
-    GtkTreeIter iter;
-    KatzeItem* item;
-
-    tree_view = GTK_TREE_VIEW (browser->panel_history);
-    if (katze_tree_view_get_selected_iter (tree_view, &model, &iter))
-    {
-        gtk_tree_model_get (model, &iter, 0, &item, -1);
-        if (!KATZE_IS_ARRAY (item))
-            midori_browser_edit_bookmark_dialog_new (browser, item, TRUE);
-        g_object_unref (item);
-    }
-}
-
 static void
 _action_undo_tab_close_activate (GtkAction*     action,
                                  MidoriBrowser* browser)
@@ -3214,16 +2871,6 @@ static const GtkActionEntry entries[] = {
  { "BookmarkAdd", STOCK_BOOKMARK_ADD,
    NULL, "<Ctrl>d",
    N_("Add a new bookmark"), G_CALLBACK (_action_bookmark_add_activate) },
- { "HistoryDelete", GTK_STOCK_DELETE,
-   NULL, "",
-   N_("Delete the selected history item"), G_CALLBACK (_action_history_delete_activate) },
- { "HistoryClear", GTK_STOCK_CLEAR,
-   NULL, "",
-   N_("Clear the entire history"), G_CALLBACK (_action_history_clear_activate) },
- { "HistoryAddBookmark", STOCK_BOOKMARK_ADD,
-   NULL, "",
-   N_("Bookmark the selected history item"),
-   G_CALLBACK (_action_history_add_bookmark_activate) },
  { "Tools", NULL, N_("_Tools") },
  { "ManageSearchEngines", GTK_STOCK_PROPERTIES,
    N_("_Manage Search Engines"), "<Ctrl><Alt>s",
@@ -3446,12 +3093,6 @@ static const gchar* ui_markup =
   "</menubar>"
   "<toolbar name='toolbar_navigation'>"
   "</toolbar>"
-  "<toolbar name='toolbar_history'>"
-   "<toolitem action='HistoryAddBookmark'/>"
-   "<toolitem action='HistoryDelete'/>"
-   "<separator expand='true' />"
-   "<toolitem action='HistoryClear' position='bottom' />"
-  "</toolbar>"
  "</ui>";
 
 static void
@@ -3482,54 +3123,10 @@ midori_browser_entry_clear_icon_released_cb (GtkIconEntry* entry,
         gtk_entry_set_text (GTK_ENTRY (entry), "");
 }
 
-static void
-_tree_store_insert_history_item (GtkTreeStore* treestore,
-                                 GtkTreeIter*  parent,
-                                 KatzeItem*    item,
-                                 gint64        day)
-{
-    GtkTreeIter iter;
-    KatzeItem* child;
-    guint i, n;
-    GtkTreeIter* piter;
-    gint64 pday;
-    gint64 age = -1;
-
-    g_return_if_fail (KATZE_IS_ITEM (item));
-
-    if (KATZE_IS_ARRAY (item))
-    {
-        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);
-            g_object_unref (item);
-            piter = &iter;
-        }
-        n = katze_array_get_length (KATZE_ARRAY (item));
-        for (i = 0; i < n; i++)
-        {
-            child = katze_array_get_nth_item (KATZE_ARRAY (item), i);
-            _tree_store_insert_history_item (treestore, piter, child, day);
-        }
-    }
-    else
-    {
-        gtk_tree_store_insert_with_values (treestore, &iter, parent,
-                                           0, 0, item, 1, age, -1);
-        g_object_unref (item);
-    }
-}
-
 static void
 midori_browser_new_history_item (MidoriBrowser* browser,
                                  KatzeItem*     item)
 {
-    GtkTreeView* treeview;
-    GtkTreeModel* treemodel;
-    GtkTreeIter iter;
     KatzeArray* parent;
     gint i;
     gboolean found;
@@ -3540,34 +3137,24 @@ midori_browser_new_history_item (MidoriBrowser* browser,
     gint64 newage;
     gchar token[50];
 
-    if (!katze_object_get_boolean (browser->settings, "remember-last-visited-pages"))
-        return;
-
-    treeview = GTK_TREE_VIEW (browser->panel_history);
-    treemodel = gtk_tree_view_get_model (treeview);
-
     now = time (NULL);
     katze_item_set_added (item, now);
     day = sokoke_time_t_to_julian (&now);
 
     found = FALSE;
     i = 0;
-    while (gtk_tree_model_iter_nth_child (treemodel, &iter, NULL, i++))
+    while ((parent = katze_array_get_nth_item (browser->history, i++)))
     {
-        gtk_tree_model_get (treemodel, &iter, 0, &parent, 1, &age, -1);
         pday = katze_item_get_added (KATZE_ITEM (parent));
+        age = katze_item_get_added (item);
         newage = day - pday;
         if (newage == 0)
         {
             found = TRUE;
-            _tree_store_insert_history_item (GTK_TREE_STORE (treemodel),
-                                             &iter, item, day);
             katze_array_add_item (parent, item);
         }
         if (age != newage)
-            gtk_tree_store_set (GTK_TREE_STORE (treemodel),
-                                &iter, 1, newage, -1);
-        g_object_unref (parent);
+            katze_item_set_added (item, newage);
     }
     if (!found)
     {
@@ -3577,11 +3164,22 @@ midori_browser_new_history_item (MidoriBrowser* browser,
         katze_item_set_token (KATZE_ITEM (parent), token);
         katze_array_add_item (browser->history, parent);
         katze_array_add_item (parent, item);
-        _tree_store_insert_history_item (GTK_TREE_STORE (treemodel), NULL,
-                                         KATZE_ITEM (parent), day);
     }
 }
 
+static void
+midori_browser_history_remove_item_cb (KatzeArray*    folder,
+                                       KatzeItem*     item,
+                                       MidoriBrowser* browser)
+{
+    GtkAction* location_action = _action_by_name (browser, "Location");
+    midori_location_action_delete_item_from_uri (
+        MIDORI_LOCATION_ACTION (location_action), katze_item_get_uri (item));
+    g_signal_handlers_disconnect_by_func (folder,
+                                          midori_browser_history_remove_item_cb,
+                                          browser);
+}
+
 static void
 _location_action_insert_history_item (MidoriLocationAction* action,
                                       MidoriBrowser*        browser,
@@ -3608,6 +3206,8 @@ _location_action_insert_history_item (MidoriLocationAction* action,
         midori_location_action_add_item (action, uri,
             pixbuf, katze_item_get_name (item));
         g_object_unref (pixbuf);
+        g_signal_connect (katze_item_get_parent (item), "remove-item",
+            G_CALLBACK (midori_browser_history_remove_item_cb), browser);
     }
 }
 
@@ -3615,15 +3215,7 @@ static void
 midori_browser_history_clear_cb (KatzeArray*    history,
                                  MidoriBrowser* browser)
 {
-    GtkTreeView* treeview;
-    GtkTreeStore* store;
-    GtkAction* location_action;
-
-    treeview = GTK_TREE_VIEW (browser->panel_history);
-    store = GTK_TREE_STORE (gtk_tree_view_get_model (treeview));
-    gtk_tree_store_clear (store);
-
-    location_action = _action_by_name (browser, "Location");
+    GtkAction* location_action = _action_by_name (browser, "Location");
     midori_location_action_clear (MIDORI_LOCATION_ACTION (location_action));
 }
 
@@ -3631,8 +3223,6 @@ static void
 midori_browser_set_history (MidoriBrowser* browser,
                             KatzeArray*    history)
 {
-    GtkTreeView* treeview;
-    GtkTreeModel* treemodel;
     GtkAction* action;
     time_t now;
     gint64 day;
@@ -3662,11 +3252,6 @@ midori_browser_set_history (MidoriBrowser* browser,
     now = time (NULL);
     day = sokoke_time_t_to_julian (&now);
 
-    treeview = GTK_TREE_VIEW (browser->panel_history);
-    treemodel = gtk_tree_view_get_model (treeview);
-    _tree_store_insert_history_item (GTK_TREE_STORE (treemodel), NULL,
-                                     KATZE_ITEM (browser->history), day);
-
     action = _action_by_name (browser, "Location");
     midori_location_action_freeze (MIDORI_LOCATION_ACTION (action));
     _location_action_insert_history_item (MIDORI_LOCATION_ACTION (action),
@@ -3690,13 +3275,6 @@ midori_browser_init (MidoriBrowser* browser)
     GtkWidget* hbox;
     GtkWidget* hpaned;
     GtkWidget* vpaned;
-    GtkWidget* box;
-    GtkTreeViewColumn* column;
-    GtkCellRenderer* renderer_text;
-    GtkCellRenderer* renderer_pixbuf;
-    GtkTreeStore* treestore;
-    GtkWidget* treeview;
-    GtkWidget* toolbar;
     GtkToolItem* toolitem;
     GtkRcStyle* rcstyle;
     GtkWidget* scrolled;
@@ -3963,49 +3541,6 @@ midori_browser_init (MidoriBrowser* browser)
                       G_CALLBACK (midori_panel_close_cb), browser);
     gtk_paned_pack1 (GTK_PANED (hpaned), browser->panel, FALSE, FALSE);
 
-    /* History */
-    box = gtk_vbox_new (FALSE, 0);
-    treestore = gtk_tree_store_new (2, KATZE_TYPE_ITEM, G_TYPE_INT64);
-    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 ();
-    renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
-    gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
-    gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf,
-        (GtkTreeCellDataFunc)midori_browser_history_render_icon_cb,
-        treeview, NULL);
-    renderer_text = gtk_cell_renderer_text_new ();
-    gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
-    gtk_tree_view_column_set_cell_data_func (column, renderer_text,
-        (GtkTreeCellDataFunc)midori_browser_history_render_text_cb,
-        treeview, NULL);
-    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
-    g_object_unref (treestore);
-    g_object_connect (treeview,
-                      "signal::row-activated",
-                      midori_panel_history_row_activated_cb, browser,
-                      "signal::cursor-changed",
-                      midori_panel_history_cursor_or_row_changed_cb, browser,
-                      "signal::columns-changed",
-                      midori_panel_history_cursor_or_row_changed_cb, browser,
-                      "signal::button-release-event",
-                      midori_panel_history_button_release_event_cb, browser,
-                      "signal::key-release-event",
-                      midori_panel_history_key_release_event_cb, browser,
-                      "signal::popup-menu",
-                      midori_panel_history_popup_menu_cb, browser,
-                      NULL);
-    midori_panel_history_cursor_or_row_changed_cb (GTK_TREE_VIEW (treeview),
-                                                   browser);
-    gtk_box_pack_start (GTK_BOX (box), treeview, TRUE, TRUE, 0);
-    browser->panel_history = treeview;
-    gtk_widget_show_all (box);
-    toolbar = gtk_ui_manager_get_widget (ui_manager, "/toolbar_history");
-    gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_MENU);
-    gtk_widget_show (toolbar);
-    midori_panel_append_widget (MIDORI_PANEL (browser->panel),
-                                box, STOCK_HISTORY, _("History"), toolbar);
-
     /* Notebook, containing all views */
     vpaned = gtk_vpaned_new ();
     gtk_paned_pack2 (GTK_PANED (hpaned), vpaned, FALSE, FALSE);
diff --git a/panels/midori-history.c b/panels/midori-history.c
new file mode 100644 (file)
index 0000000..4a41695
--- /dev/null
@@ -0,0 +1,950 @@
+/*
+ Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ See the file COPYING for the full license text.
+*/
+
+#include "midori-history.h"
+
+#include "midori-app.h"
+#include "midori-browser.h"
+#include "midori-stock.h"
+#include "midori-view.h"
+#include "midori-viewable.h"
+
+#include "sokoke.h"
+
+#include <glib/gi18n.h>
+#include <string.h>
+
+#include <katze/katze.h>
+#include <gdk/gdkkeysyms.h>
+
+void
+midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
+                                         KatzeItem*     bookmark,
+                                         gboolean       new_bookmark);
+
+struct _MidoriHistory
+{
+    GtkVBox parent_instance;
+
+    GtkWidget* toolbar;
+    GtkWidget* bookmark;
+    GtkWidget* delete;
+    GtkWidget* clear;
+    GtkWidget* treeview;
+    MidoriApp* app;
+    KatzeArray* array;
+    KatzeNet* net;
+};
+
+struct _MidoriHistoryClass
+{
+    GtkVBoxClass parent_class;
+};
+
+static void
+midori_history_viewable_iface_init (MidoriViewableIface* iface);
+
+G_DEFINE_TYPE_WITH_CODE (MidoriHistory, midori_history, GTK_TYPE_VBOX,
+                         G_IMPLEMENT_INTERFACE (MIDORI_TYPE_VIEWABLE,
+                             midori_history_viewable_iface_init));
+
+enum
+{
+    PROP_0,
+
+    PROP_APP
+};
+
+static void
+midori_history_set_property (GObject*      object,
+                             guint         prop_id,
+                             const GValue* value,
+                             GParamSpec*   pspec);
+
+static void
+midori_history_get_property (GObject*    object,
+                             guint       prop_id,
+                             GValue*     value,
+                             GParamSpec* pspec);
+
+static void
+midori_history_class_init (MidoriHistoryClass* class)
+{
+    GObjectClass* gobject_class;
+    GParamFlags flags;
+
+    gobject_class = G_OBJECT_CLASS (class);
+    gobject_class->set_property = midori_history_set_property;
+    gobject_class->get_property = midori_history_get_property;
+
+    flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_APP,
+                                     g_param_spec_object (
+                                     "app",
+                                     "App",
+                                     "The app",
+                                     MIDORI_TYPE_APP,
+                                     flags));
+}
+
+static const gchar*
+midori_history_get_label (MidoriViewable* viewable)
+{
+    return _("History");
+}
+
+static const gchar*
+midori_history_get_stock_id (MidoriViewable* viewable)
+{
+    return STOCK_HISTORY;
+}
+
+static void
+midori_history_add_clicked_cb (GtkWidget* toolitem)
+{
+    GtkWidget* browser = gtk_widget_get_toplevel (toolitem);
+    /* FIXME: Take selected folder into account */
+    midori_browser_edit_bookmark_dialog_new (MIDORI_BROWSER (browser),
+                                             NULL, TRUE);
+}
+
+static void
+midori_history_delete_clicked_cb (GtkWidget*     toolitem,
+                                  MidoriHistory* history)
+{
+    GtkTreeModel* model;
+    GtkTreeIter iter;
+
+    if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (history->treeview),
+                                           &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);
+
+        g_object_unref (item);
+    }
+}
+
+static void
+midori_history_clear_clicked_cb (GtkWidget*     toolitem,
+                                 MidoriHistory* history)
+{
+    GtkWidget* browser;
+    GtkWidget* dialog;
+    gint result;
+
+    browser = gtk_widget_get_toplevel (GTK_WIDGET (history));
+    dialog = gtk_message_dialog_new (GTK_WINDOW (browser),
+        GTK_DIALOG_DESTROY_WITH_PARENT,
+        GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
+        _("Are you sure you want to remove all history items?"));
+    result = gtk_dialog_run (GTK_DIALOG (dialog));
+    gtk_widget_destroy (dialog);
+    if (result != GTK_RESPONSE_YES)
+        return;
+
+    katze_array_clear (history->array);
+}
+
+static void
+midori_history_cursor_or_row_changed_cb (GtkTreeView*   treeview,
+                                         MidoriHistory* history)
+{
+    GtkTreeModel* model;
+    GtkTreeIter iter;
+    KatzeItem* item;
+
+    if (!history->bookmark)
+        return;
+
+    if (katze_tree_view_get_selected_iter (treeview, &model, &iter))
+    {
+        gboolean is_page;
+
+        gtk_tree_model_get (model, &iter, 0, &item, -1);
+
+        is_page = !KATZE_IS_ARRAY (item) && katze_item_get_uri (item);
+        gtk_widget_set_sensitive (history->bookmark, is_page);
+        gtk_widget_set_sensitive (history->delete, TRUE);
+        gtk_widget_set_sensitive (history->clear, TRUE);
+
+        g_object_unref (item);
+    }
+    else
+    {
+        gtk_widget_set_sensitive (history->bookmark, FALSE);
+        gtk_widget_set_sensitive (history->delete, FALSE);
+        gtk_widget_set_sensitive (history->clear, FALSE);
+    }
+}
+
+static GtkWidget*
+midori_history_get_toolbar (MidoriViewable* viewable)
+{
+    MidoriHistory* history = MIDORI_HISTORY (viewable);
+
+    if (!history->toolbar)
+    {
+        GtkWidget* toolbar;
+        GtkToolItem* toolitem;
+
+        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;
+        toolitem = gtk_tool_button_new_from_stock (STOCK_BOOKMARK_ADD);
+        gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
+                                     _("Bookmark the selected history item"));
+        gtk_tool_item_set_is_important (toolitem, TRUE);
+        g_signal_connect (toolitem, "clicked",
+            G_CALLBACK (midori_history_add_clicked_cb), history);
+        gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
+        gtk_widget_show (GTK_WIDGET (toolitem));
+        history->bookmark = GTK_WIDGET (toolitem);
+        toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_DELETE);
+        gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
+                                     _("Delete the selected history item"));
+        g_signal_connect (toolitem, "clicked",
+            G_CALLBACK (midori_history_delete_clicked_cb), history);
+        gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
+        gtk_widget_show (GTK_WIDGET (toolitem));
+        history->delete = GTK_WIDGET (toolitem);
+        toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_CLEAR);
+        gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
+                                     _("Clear the entire history"));
+        g_signal_connect (toolitem, "clicked",
+            G_CALLBACK (midori_history_clear_clicked_cb), history);
+        gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
+        gtk_widget_show (GTK_WIDGET (toolitem));
+        history->clear = GTK_WIDGET (toolitem);
+        midori_history_cursor_or_row_changed_cb (
+            GTK_TREE_VIEW (history->treeview), history);
+        g_signal_connect (history->bookmark, "destroy",
+            G_CALLBACK (gtk_widget_destroyed), &history->bookmark);
+        g_signal_connect (history->delete, "destroy",
+            G_CALLBACK (gtk_widget_destroyed), &history->delete);
+        g_signal_connect (history->clear, "destroy",
+            G_CALLBACK (gtk_widget_destroyed), &history->clear);
+    }
+
+    return history->toolbar;
+}
+
+static void
+midori_history_viewable_iface_init (MidoriViewableIface* iface)
+{
+    iface->get_stock_id = midori_history_get_stock_id;
+    iface->get_label = midori_history_get_label;
+    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)
+{
+    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));
+        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));
+
+    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, G_MAXINT, 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, G_MAXINT, 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));
+
+    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);
+}
+
+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, n;
+
+        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);
+            g_object_unref (item);
+            piter = &iter;
+        }
+        n = katze_array_get_length (KATZE_ARRAY (item));
+        for (i = 0; i < n; i++)
+        {
+            KatzeItem* child;
+
+            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)
+{
+    GtkTreeModel* model;
+
+    if (history->array)
+    {
+        midori_history_disconnect_folder (history, history->array);
+        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);
+
+        /* FIXME: Dereference the app on finalization */
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (history->treeview));
+        midori_history_insert_item (history, GTK_TREE_STORE (model),
+            NULL, KATZE_ITEM (g_object_ref (history->array)), day);
+    }
+}
+
+static void
+midori_history_set_property (GObject*      object,
+                             guint         prop_id,
+                             const GValue* value,
+                             GParamSpec*   pspec)
+{
+    MidoriHistory* history = MIDORI_HISTORY (object);
+
+    switch (prop_id)
+    {
+    case PROP_APP:
+        midori_history_set_app (history, g_value_get_object (value));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+midori_history_get_property (GObject*    object,
+                             guint       prop_id,
+                             GValue*     value,
+                             GParamSpec* pspec)
+{
+    MidoriHistory* history = MIDORI_HISTORY (object);
+
+    switch (prop_id)
+    {
+    case PROP_APP:
+        g_value_set_object (value, history->app);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+midori_history_treeview_render_icon_cb (GtkTreeViewColumn* column,
+                                        GtkCellRenderer*   renderer,
+                                        GtkTreeModel*      model,
+                                        GtkTreeIter*       iter,
+                                        GtkWidget*         treeview)
+{
+    KatzeItem* item;
+    GdkPixbuf* pixbuf = NULL;
+
+    gtk_tree_model_get (model, iter, 0, &item, -1);
+
+    g_assert (KATZE_IS_ITEM (item));
+
+    if (KATZE_IS_ARRAY (item))
+        pixbuf = gtk_widget_render_icon (treeview, GTK_STOCK_DIRECTORY,
+                                         GTK_ICON_SIZE_MENU, NULL);
+    else
+        pixbuf = katze_net_load_icon (
+            MIDORI_HISTORY (gtk_widget_get_parent (treeview))->net,
+            katze_item_get_uri (item), NULL, treeview, NULL);
+
+    g_object_set (renderer, "pixbuf", pixbuf, NULL);
+
+    if (pixbuf)
+        g_object_unref (pixbuf);
+
+    g_object_unref (item);
+}
+
+static void
+midori_history_treeview_render_text_cb (GtkTreeViewColumn* column,
+                                        GtkCellRenderer*   renderer,
+                                        GtkTreeModel*      model,
+                                        GtkTreeIter*       iter,
+                                        GtkWidget*         treeview)
+{
+    KatzeItem* item;
+    gint64 age;
+
+    gtk_tree_model_get (model, iter, 0, &item, 1, &age, -1);
+
+    g_assert (KATZE_IS_ITEM (item));
+
+    if (KATZE_IS_ARRAY (item))
+    {
+        gchar* sdate;
+
+        g_assert (age >= 0);
+
+        if (age > 7)
+        {
+            g_object_set (renderer, "text", katze_item_get_token (item), NULL);
+        }
+        else if (age > 6)
+        {
+            sdate = g_strdup_printf (_("A week ago"));
+            g_object_set (renderer, "text", sdate, NULL);
+            g_free (sdate);
+        }
+        else if (age > 1)
+        {
+            sdate = g_strdup_printf (_("%d days ago"), (gint)age);
+            g_object_set (renderer, "text", sdate, NULL);
+            g_free (sdate);
+        }
+        else
+        {
+            if (age == 0)
+                sdate = _("Today");
+            else
+                sdate = _("Yesterday");
+            g_object_set (renderer, "text", sdate, NULL);
+        }
+    }
+    else
+        g_object_set (renderer, "text", katze_item_get_name (item), NULL);
+
+    g_object_unref (item);
+}
+
+static void
+midori_history_row_activated_cb (GtkTreeView*       treeview,
+                                   GtkTreePath*       path,
+                                   GtkTreeViewColumn* column,
+                                   MidoriHistory*   history)
+{
+    GtkTreeModel* model;
+    GtkTreeIter iter;
+    KatzeItem* item;
+    const gchar* uri;
+
+    model = gtk_tree_view_get_model (treeview);
+
+    if (gtk_tree_model_get_iter (model, &iter, path))
+    {
+        gtk_tree_model_get (model, &iter, 0, &item, -1);
+        uri = katze_item_get_uri (item);
+        if (uri && *uri)
+        {
+            GtkWidget* browser;
+
+            browser = gtk_widget_get_toplevel (GTK_WIDGET (history));
+            midori_browser_set_current_uri (MIDORI_BROWSER (browser), uri);
+        }
+
+        g_object_unref (item);
+    }
+}
+
+static void
+midori_history_popup_item (GtkWidget*     menu,
+                           const gchar*   stock_id,
+                           const gchar*   label,
+                           KatzeItem*     item,
+                           gpointer       callback,
+                           MidoriHistory* history)
+{
+    const gchar* uri;
+    GtkWidget* menuitem;
+
+    uri = katze_item_get_uri (item);
+
+    menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
+    if (label)
+        gtk_label_set_text_with_mnemonic (GTK_LABEL (gtk_bin_get_child (
+        GTK_BIN (menuitem))), label);
+    if (!strcmp (stock_id, GTK_STOCK_EDIT))
+        gtk_widget_set_sensitive (menuitem,
+            KATZE_IS_ARRAY (item) || uri != NULL);
+    else if (strcmp (stock_id, GTK_STOCK_DELETE))
+        gtk_widget_set_sensitive (menuitem, uri != NULL);
+    g_object_set_data (G_OBJECT (menuitem), "KatzeItem", item);
+    g_signal_connect (menuitem, "activate", G_CALLBACK (callback), history);
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+    gtk_widget_show (menuitem);
+}
+
+static void
+midori_history_open_activate_cb (GtkWidget*     menuitem,
+                                 MidoriHistory* history)
+{
+    KatzeItem* item;
+    const gchar* uri;
+
+    item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
+    uri = katze_item_get_uri (item);
+
+    if (uri && *uri)
+    {
+        GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (history));
+        midori_browser_set_current_uri (MIDORI_BROWSER (browser), uri);
+    }
+}
+
+static void
+midori_history_open_in_tab_activate_cb (GtkWidget*     menuitem,
+                                        MidoriHistory* history)
+{
+    KatzeItem* item;
+    const gchar* uri;
+    guint n;
+
+    item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
+    uri = katze_item_get_uri (item);
+
+    if (uri && *uri)
+    {
+        GtkWidget* browser;
+        MidoriWebSettings* settings;
+
+        browser = gtk_widget_get_toplevel (GTK_WIDGET (history));
+        n = midori_browser_add_item (MIDORI_BROWSER (browser), item);
+        settings = katze_object_get_object (browser, "settings");
+        if (!katze_object_get_boolean (settings, "open-tabs-in-the-background"))
+            midori_browser_set_current_page (MIDORI_BROWSER (browser), n);
+    }
+}
+
+static void
+midori_history_open_in_window_activate_cb (GtkWidget*     menuitem,
+                                           MidoriHistory* history)
+{
+    KatzeItem* item;
+    const gchar* uri;
+
+    item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
+    uri = katze_item_get_uri (item);
+
+    if (uri && *uri)
+    {
+        GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (history));
+        g_signal_emit_by_name (browser, "new-window", uri);
+    }
+}
+
+static void
+midori_history_bookmark_activate_cb (GtkWidget*     menuitem,
+                                     MidoriHistory* history)
+{
+    KatzeItem* item;
+    const gchar* uri;
+
+    item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
+    uri = katze_item_get_uri (item);
+
+    if (uri && *uri)
+    {
+        GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (history));
+        midori_browser_edit_bookmark_dialog_new (MIDORI_BROWSER (browser), item, TRUE);
+    }
+}
+
+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,
+                      KatzeItem*      item,
+                      MidoriHistory*  history)
+{
+    GtkWidget* menu;
+    GtkWidget* menuitem;
+
+    menu = gtk_menu_new ();
+    midori_history_popup_item (menu, GTK_STOCK_OPEN, NULL,
+        item, midori_history_open_activate_cb, history);
+    midori_history_popup_item (menu, STOCK_TAB_NEW, _("Open in New _Tab"),
+        item, midori_history_open_in_tab_activate_cb, history);
+    midori_history_popup_item (menu, STOCK_WINDOW_NEW, _("Open in New _Window"),
+        item, midori_history_open_in_window_activate_cb, history);
+    if (!KATZE_IS_ARRAY (item))
+        midori_history_popup_item (menu, STOCK_BOOKMARK_ADD, NULL,
+            item, midori_history_bookmark_activate_cb, history);
+    menuitem = gtk_separator_menu_item_new ();
+    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);
+
+    sokoke_widget_popup (widget, GTK_MENU (menu),
+                         event, SOKOKE_MENU_POSITION_CURSOR);
+}
+
+static gboolean
+midori_history_button_release_event_cb (GtkWidget*      widget,
+                                        GdkEventButton* event,
+                                        MidoriHistory*  history)
+{
+    GtkTreeModel* model;
+    GtkTreeIter iter;
+
+    if (event->button != 2 && event->button != 3)
+        return FALSE;
+
+    if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
+    {
+        KatzeItem* item;
+
+        gtk_tree_model_get (model, &iter, 0, &item, -1);
+
+        if (event->button == 2)
+        {
+            const gchar* uri = katze_item_get_uri (item);
+
+            if (uri && *uri)
+            {
+                GtkWidget* browser;
+                gint n;
+
+                browser = gtk_widget_get_toplevel (widget);
+                n = midori_browser_add_uri (MIDORI_BROWSER (browser), uri);
+                midori_browser_set_current_page (MIDORI_BROWSER (browser), n);
+            }
+        }
+        else
+            midori_history_popup (widget, event, item, history);
+
+        g_object_unref (item);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static gboolean
+midori_history_key_release_event_cb (GtkWidget*     widget,
+                                     GdkEventKey*   event,
+                                     MidoriHistory* history)
+{
+    GtkTreeModel* model;
+    GtkTreeIter iter;
+
+    if (event->keyval != GDK_Delete)
+        return FALSE;
+
+    if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
+    {
+        KatzeItem* item;
+        KatzeArray* parent;
+
+        gtk_tree_model_get (model, &iter, 0, &item, -1);
+
+        parent = katze_item_get_parent (item);
+        katze_array_remove_item (parent, item);
+
+        g_object_unref (item);
+    }
+
+    return FALSE;
+}
+
+static void
+midori_history_popup_menu_cb (GtkWidget*     widget,
+                              MidoriHistory* history)
+{
+    GtkTreeModel* model;
+    GtkTreeIter iter;
+    KatzeItem* item;
+
+    if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
+    {
+        gtk_tree_model_get (model, &iter, 0, &item, -1);
+        midori_history_popup (widget, NULL, item, history);
+        g_object_unref (item);
+    }
+}
+
+static void
+midori_history_init (MidoriHistory* history)
+{
+    GtkTreeStore* model;
+    GtkWidget* treeview;
+    GtkTreeViewColumn* column;
+    GtkCellRenderer* renderer_pixbuf;
+    GtkCellRenderer* renderer_text;
+
+    history->net = katze_net_new ();
+    /* FIXME: Dereference the net on finalization */
+
+    /* Create the treeview */
+    model = gtk_tree_store_new (2, KATZE_TYPE_ITEM, G_TYPE_INT64);
+    treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
+    gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
+    column = gtk_tree_view_column_new ();
+    renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
+    gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
+    gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf,
+        (GtkTreeCellDataFunc)midori_history_treeview_render_icon_cb,
+        treeview, NULL);
+    renderer_text = gtk_cell_renderer_text_new ();
+    gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
+    gtk_tree_view_column_set_cell_data_func (column, renderer_text,
+        (GtkTreeCellDataFunc)midori_history_treeview_render_text_cb,
+        treeview, NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+    g_object_unref (model);
+    g_object_connect (treeview,
+                      "signal::row-activated",
+                      midori_history_row_activated_cb, history,
+                      "signal::cursor-changed",
+                      midori_history_cursor_or_row_changed_cb, history,
+                      "signal::columns-changed",
+                      midori_history_cursor_or_row_changed_cb, history,
+                      "signal::button-release-event",
+                      midori_history_button_release_event_cb, history,
+                      "signal::key-release-event",
+                      midori_history_key_release_event_cb, history,
+                      "signal::popup-menu",
+                      midori_history_popup_menu_cb, history,
+                      NULL);
+    gtk_widget_show (treeview);
+    gtk_box_pack_start (GTK_BOX (history), treeview, TRUE, TRUE, 0);
+    history->treeview = treeview;
+}
+
+/**
+ * midori_history_new:
+ *
+ * Creates a new empty history.
+ *
+ * Return value: a new #MidoriHistory
+ *
+ * Since: 0.1.3
+ **/
+GtkWidget*
+midori_history_new (void)
+{
+    MidoriHistory* history = g_object_new (MIDORI_TYPE_HISTORY, NULL);
+
+    return GTK_WIDGET (history);
+}
diff --git a/panels/midori-history.h b/panels/midori-history.h
new file mode 100644 (file)
index 0000000..fc496ee
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 2009 Christian Dywan <christian@twotoasts.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ See the file COPYING for the full license text.
+*/
+
+#ifndef __MIDORI_HISTORY_H__
+#define __MIDORI_HISTORY_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define MIDORI_TYPE_HISTORY \
+    (midori_history_get_type ())
+#define MIDORI_HISTORY(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_HISTORY, MidoriHistory))
+#define MIDORI_HISTORY_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_HISTORY, MidoriHistoryClass))
+#define MIDORI_IS_HISTORY(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_HISTORY))
+#define MIDORI_IS_HISTORY_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_HISTORY))
+#define MIDORI_HISTORY_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_HISTORY, MidoriHistoryClass))
+
+typedef struct _MidoriHistory                MidoriHistory;
+typedef struct _MidoriHistoryClass           MidoriHistoryClass;
+
+GType
+midori_history_get_type               (void);
+
+GtkWidget*
+midori_history_new                    (void);
+
+G_END_DECLS
+
+#endif /* __MIDORI_HISTORY_H__ */
index ab4d273cfa47f09e3b621266cc4700d00143e516..5fbbe2d14eca5146113aa635e0b0003dec4d1f61 100644 (file)
@@ -16,6 +16,7 @@ panels/midori-addons.c
 panels/midori-bookmarks.c
 panels/midori-console.c
 panels/midori-extensions.c
+panels/midori-history.c
 panels/midori-plugins.c
 katze/katze-http-auth.c
 katze/katze-throbber.c