[epiphany] Rework personal data dialog using new WebKit API



commit afe0f013631864bbb603b14779d23c51168c2c89
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Tue Jan 17 12:48:37 2017 +0100

    Rework personal data dialog using new WebKit API
    
    It allows to delete data types for all websites modified since a given
    period of time, similar to firefox and chromium. But when selecting to
    clear data from the beginning of time it also allows you to only delete
    the data for particular domains.
    It only offers to delete data that is actually found.
    Other kind of data not handled by WebKitWebsiteDataManager like cookies,
    passwords and history navugation has been removed, since it was
    actually redundant here. The cookies dialog already allows to clear
    cookies, the password dialog allows to clear passwords and same for the
    history dialog. The only regression would be the favicons, but I think
    it would be better to make WebKitWebsiteDataManager handle favicons
    instead of having them as a special case here.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=741447

 src/clear-data-dialog.c                |  428 +++++++++++++++++++++++++++-----
 src/resources/gtk/clear-data-dialog.ui |  233 +++++++++++++-----
 2 files changed, 535 insertions(+), 126 deletions(-)
---
diff --git a/src/clear-data-dialog.c b/src/clear-data-dialog.c
index 4f38df8..7f1c04f 100644
--- a/src/clear-data-dialog.c
+++ b/src/clear-data-dialog.c
@@ -19,56 +19,165 @@
  */
 
 #include "config.h"
+#include "clear-data-dialog.h"
 
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <string.h>
-
-#define SECRET_API_SUBJECT_TO_CHANGE
-#include <libsecret/secret.h>
 #include <webkit2/webkit2.h>
 
 #include "ephy-form-auth-data.h"
 #include "ephy-history-service.h"
 #include "ephy-embed-shell.h"
 
-#include "clear-data-dialog.h"
+typedef enum {
+  TIMESPAN_HOUR,
+  TIMESPAN_DAY,
+  TIMESPAN_WEEK,
+  TIMESPAN_MONTH,
+  TIMESPAN_FOREVER
+} Timespan;
 
 struct _ClearDataDialog {
   GtkDialog parent_instance;
 
-  GtkWidget *cache_checkbutton;
-  GtkWidget *history_checkbutton;
-  GtkWidget *passwords_checkbutton;
-  GtkWidget *cookies_checkbutton;
   GtkWidget *clear_button;
+  GtkWidget *treeview;
+  GtkTreeModel *treestore;
+  GtkTreeModelFilter *treemodelfilter;
+  GtkWidget *timespan_combo;
+  GtkWidget *search_entry;
+  GtkSpinner *spinner;
+  GtkStack *stack;
 
-  guint num_checked;
+  Timespan timespan;
+  GCancellable *cancellable;
+};
+
+enum {
+  TYPE_COLUMN,
+  ACTIVE_COLUMN,
+  NAME_COLUMN,
+  DATA_COLUMN,
+  SENSITIVE_COLUMN
 };
 
 G_DEFINE_TYPE (ClearDataDialog, clear_data_dialog, GTK_TYPE_DIALOG)
 
-static WebKitCookieManager *
-get_cookie_manager (void)
+#define PERSISTENT_DATA_TYPES WEBKIT_WEBSITE_DATA_DISK_CACHE | \
+  WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE | \
+  WEBKIT_WEBSITE_DATA_LOCAL_STORAGE | \
+  WEBKIT_WEBSITE_DATA_WEBSQL_DATABASES | \
+  WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES | \
+  WEBKIT_WEBSITE_DATA_PLUGIN_DATA
+
+typedef struct {
+  WebKitWebsiteDataTypes type;
+  gboolean initial_state;
+  const char* name;
+} DataEntry;
+
+static const DataEntry data_entries[] = {
+  { WEBKIT_WEBSITE_DATA_DISK_CACHE, TRUE, N_("HTTP disk cache") },
+  { WEBKIT_WEBSITE_DATA_LOCAL_STORAGE, FALSE, N_("Local storage data") },
+  { WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE, TRUE, N_("Offline web application cache") },
+  { WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES, FALSE, N_("IndexedDB databases") },
+  { WEBKIT_WEBSITE_DATA_WEBSQL_DATABASES, FALSE, N_("WebSQL databases") },
+  { WEBKIT_WEBSITE_DATA_PLUGIN_DATA, FALSE, N_("Plugins data") }
+};
+
+static WebKitWebsiteDataManager *
+get_website_data_manger (void)
 {
   WebKitWebContext *web_context;
-  EphyEmbedShell *shell = ephy_embed_shell_get_default ();
 
-  web_context = ephy_embed_shell_get_web_context (shell);
-  return webkit_web_context_get_cookie_manager (web_context);
+  web_context = ephy_embed_shell_get_web_context (ephy_embed_shell_get_default ());
+  return webkit_web_context_get_website_data_manager (web_context);
+}
+
+static inline GTimeSpan
+get_timespan_for_combo_value (Timespan timespan)
+{
+  switch (timespan) {
+  case TIMESPAN_HOUR:
+    return G_TIME_SPAN_HOUR;
+  case TIMESPAN_DAY:
+    return G_TIME_SPAN_DAY;
+  case TIMESPAN_WEEK:
+    return G_TIME_SPAN_DAY * 7;
+  case TIMESPAN_MONTH:
+    return G_TIME_SPAN_DAY * 7 * 4;
+  case TIMESPAN_FOREVER:
+    return 0;
+  default:
+    break;
+  }
+
+  g_assert_not_reached ();
+  return 0;
 }
 
 static void
-delete_all_passwords (ClearDataDialog *dialog)
+website_data_fetched_cb (WebKitWebsiteDataManager *manager,
+                         GAsyncResult             *result,
+                         ClearDataDialog          *dialog)
 {
-  GHashTable *attributes;
-
-  attributes = secret_attributes_build (EPHY_FORM_PASSWORD_SCHEMA, NULL);
-  secret_service_clear (NULL, EPHY_FORM_PASSWORD_SCHEMA,
-                        attributes, NULL,
-                        (GAsyncReadyCallback)secret_service_clear_finish,
-                        NULL);
-  g_hash_table_unref (attributes);
+  GList *data_list;
+  GtkTreeStore *treestore;
+  GError *error = NULL;
+
+  data_list = webkit_website_data_manager_fetch_finish (manager, result, &error);
+  if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+    g_error_free (error);
+    return;
+  }
+
+  gtk_spinner_stop (dialog->spinner);
+
+  if (!data_list) {
+    gtk_stack_set_visible_child_name (dialog->stack, "nodata");
+
+    if (error)
+      g_error_free (error);
+    return;
+  }
+
+  gtk_widget_set_sensitive (dialog->clear_button, TRUE);
+  gtk_stack_set_visible_child_name (dialog->stack, "view");
+
+  treestore = GTK_TREE_STORE (dialog->treestore);
+  for (guint i = 0; i < G_N_ELEMENTS (data_entries); i++) {
+    GtkTreeIter parent_iter;
+    gboolean empty = TRUE;
+
+    gtk_tree_store_insert_with_values (treestore, &parent_iter, NULL, -1,
+                                       TYPE_COLUMN, data_entries[i].type,
+                                       ACTIVE_COLUMN, data_entries[i].initial_state,
+                                       NAME_COLUMN, data_entries[i].name,
+                                       DATA_COLUMN, NULL,
+                                       SENSITIVE_COLUMN, TRUE,
+                                       -1);
+    for (GList *l = data_list; l && l->data; l = g_list_next (l)) {
+      WebKitWebsiteData *data = (WebKitWebsiteData *)l->data;
+
+      if (!(webkit_website_data_get_types (data) & data_entries[i].type))
+        continue;
+
+      gtk_tree_store_insert_with_values (treestore, NULL, &parent_iter, -1,
+                                         TYPE_COLUMN, data_entries[i].type,
+                                         ACTIVE_COLUMN, data_entries[i].initial_state,
+                                         NAME_COLUMN, webkit_website_data_get_name (data),
+                                         DATA_COLUMN, webkit_website_data_ref (data),
+                                         SENSITIVE_COLUMN, dialog->timespan == TIMESPAN_FOREVER,
+                                         -1);
+      empty = FALSE;
+    }
+
+    if (empty)
+      gtk_tree_store_remove (treestore, &parent_iter);
+  }
+
+  g_list_free_full (data_list, (GDestroyNotify)webkit_website_data_unref);
 }
 
 static void
@@ -76,74 +185,244 @@ clear_data_dialog_response_cb (GtkDialog       *widget,
                                int              response,
                                ClearDataDialog *dialog)
 {
-  if (response == GTK_RESPONSE_OK) {
-    if (gtk_toggle_button_get_active
-          (GTK_TOGGLE_BUTTON (dialog->history_checkbutton))) {
-      EphyEmbedShell *shell;
-      EphyHistoryService *history;
-
-      shell = ephy_embed_shell_get_default ();
-      history = EPHY_HISTORY_SERVICE (ephy_embed_shell_get_global_history_service (shell));
-      ephy_history_service_clear (history, NULL, NULL, NULL);
-    }
-    if (gtk_toggle_button_get_active
-          (GTK_TOGGLE_BUTTON (dialog->cookies_checkbutton))) {
-      WebKitCookieManager *cookie_manager;
+  GtkTreeIter top_iter;
+  WebKitWebsiteDataTypes types_to_clear = 0;
+  GList *data_to_remove = NULL;
+  WebKitWebsiteDataTypes types_to_remove = 0;
+  GTimeSpan timespan;
 
-      cookie_manager = get_cookie_manager ();
-      webkit_cookie_manager_delete_all_cookies (cookie_manager);
-    }
-    if (gtk_toggle_button_get_active
-          (GTK_TOGGLE_BUTTON (dialog->passwords_checkbutton))) {
-      delete_all_passwords (dialog);
-    }
-    if (gtk_toggle_button_get_active
-          (GTK_TOGGLE_BUTTON (dialog->cache_checkbutton))) {
-      EphyEmbedShell *shell;
-      WebKitFaviconDatabase *database;
+  if (response != GTK_RESPONSE_OK) {
+    gtk_widget_destroy (GTK_WIDGET (dialog));
+    return;
+  }
 
-      shell = ephy_embed_shell_get_default ();
+  if (!gtk_tree_model_get_iter_first (dialog->treestore, &top_iter)) {
+    gtk_widget_destroy (GTK_WIDGET (dialog));
+    return;
+  }
+
+  timespan = get_timespan_for_combo_value (dialog->timespan);
+
+  do {
+    guint type;
+    gboolean active;
+    GtkTreeIter child_iter;
+
+    gtk_tree_model_get (dialog->treestore, &top_iter,
+                        TYPE_COLUMN, &type,
+                        ACTIVE_COLUMN, &active,
+                        -1);
+    if (active) {
+      types_to_clear |= type;
+    } else if (!timespan && gtk_tree_model_iter_children (dialog->treestore, &child_iter, &top_iter)) {
+      gboolean empty = TRUE;
+
+      do {
+        WebKitWebsiteData *data;
+
+        gtk_tree_model_get (dialog->treestore, &child_iter,
+                            ACTIVE_COLUMN, &active,
+                            DATA_COLUMN, &data,
+                            -1);
 
-      ephy_embed_shell_clear_cache (shell);
+        if (active) {
+          data_to_remove = g_list_prepend (data_to_remove, data);
+          empty = FALSE;
+        } else
+          webkit_website_data_unref (data);
+      } while (gtk_tree_model_iter_next (dialog->treestore, &child_iter));
 
-      database = webkit_web_context_get_favicon_database (ephy_embed_shell_get_web_context (shell));
-      webkit_favicon_database_clear (database);
+      if (!empty)
+        types_to_remove |= type;
     }
+  } while (gtk_tree_model_iter_next (dialog->treestore, &top_iter));
+
+  if (types_to_clear) {
+    webkit_website_data_manager_clear (get_website_data_manger (),
+                                       types_to_clear, timespan,
+                                       NULL, NULL, NULL);
+  }
+
+  if (types_to_remove) {
+    webkit_website_data_manager_remove (get_website_data_manger (),
+                                        types_to_remove, data_to_remove,
+                                        NULL, NULL, NULL);
   }
 
+  g_list_free_full (data_to_remove, (GDestroyNotify)webkit_website_data_unref);
   gtk_widget_destroy (GTK_WIDGET (dialog));
 }
 
 static void
-checkbutton_toggled_cb (GtkToggleButton *toggle,
-                        ClearDataDialog *dialog)
+item_toggled_cb (GtkCellRendererToggle *renderer,
+                 const char            *path_str,
+                 ClearDataDialog       *dialog)
 {
-  if (gtk_toggle_button_get_active (toggle) == TRUE) {
-    dialog->num_checked++;
+  GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
+  GtkTreeIter iter;
+  gboolean active;
+
+  gtk_tree_model_get_iter (dialog->treestore, &iter, path);
+  gtk_tree_model_get (dialog->treestore, &iter,
+                      ACTIVE_COLUMN, &active,
+                      -1);
+  gtk_tree_store_set (GTK_TREE_STORE (dialog->treestore), &iter,
+                      ACTIVE_COLUMN, !active,
+                      -1);
+
+  if (gtk_tree_model_iter_has_child (dialog->treestore, &iter)) {
+    GtkTreeIter child_iter;
+
+    gtk_tree_model_iter_children (dialog->treestore, &child_iter, &iter);
+    do {
+      gtk_tree_store_set (GTK_TREE_STORE (dialog->treestore), &child_iter,
+                          ACTIVE_COLUMN, !active,
+                          -1);
+    } while (gtk_tree_model_iter_next (dialog->treestore, &child_iter));
   } else {
-    dialog->num_checked--;
+    GtkTreeIter parent_iter;
+
+    /* Update the parent */
+    gtk_tree_model_iter_parent (dialog->treestore, &parent_iter, &iter);
+    if (active) {
+      /* When unchecking a child we know the parent should be unchecked too */
+      gtk_tree_store_set (GTK_TREE_STORE (dialog->treestore), &parent_iter,
+                          ACTIVE_COLUMN, FALSE,
+                          -1);
+    } else {
+      GtkTreeIter child_iter;
+      gboolean all_active = TRUE;
+
+      /* When checking a child, parent should be checked if all its children are */
+      gtk_tree_model_iter_children (dialog->treestore, &child_iter, &parent_iter);
+      do {
+        gtk_tree_model_get (dialog->treestore, &child_iter,
+                            ACTIVE_COLUMN, &all_active,
+                            -1);
+      } while (all_active && gtk_tree_model_iter_next (dialog->treestore, &child_iter));
+
+      if (all_active) {
+        gtk_tree_store_set (GTK_TREE_STORE (dialog->treestore), &parent_iter,
+                            ACTIVE_COLUMN, TRUE,
+                            -1);
+      }
+    }
+  }
+
+  gtk_tree_path_free (path);
+}
+
+static gboolean
+update_item_sensitivity (GtkTreeModel    *model,
+                         GtkTreePath     *path,
+                         GtkTreeIter     *iter,
+                         ClearDataDialog *dialog)
+{
+  if (!gtk_tree_model_iter_has_child (model, iter)) {
+    gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+                        SENSITIVE_COLUMN, dialog->timespan == TIMESPAN_FOREVER,
+                        -1);
+  }
+
+  return FALSE;
+}
+
+static void
+timespan_combo_changed_cb (GtkComboBox     *combo,
+                           ClearDataDialog *dialog)
+{
+  gint active;
+  gboolean was_forever;
+
+  active = gtk_combo_box_get_active (combo);
+  was_forever = dialog->timespan == TIMESPAN_FOREVER;
+  dialog->timespan = active;
+  if (active == TIMESPAN_FOREVER || was_forever) {
+    gtk_tree_model_foreach (dialog->treestore,
+                            (GtkTreeModelForeachFunc)update_item_sensitivity,
+                            dialog);
+  }
+}
+
+static void
+search_entry_changed_cb (GtkSearchEntry  *entry,
+                         ClearDataDialog *dialog)
+{
+  gtk_tree_model_filter_refilter (dialog->treemodelfilter);
+}
+
+static gboolean
+row_visible_func (GtkTreeModel    *model,
+                  GtkTreeIter     *iter,
+                  ClearDataDialog *dialog)
+{
+  const char *search_text;
+  char *name;
+  gboolean visible;
+
+  if (gtk_tree_model_iter_has_child (model, iter))
+    return TRUE;
+
+  search_text = gtk_entry_get_text (GTK_ENTRY (dialog->search_entry));
+  if (!search_text || search_text[0] == '\0')
+    return TRUE;
+
+  gtk_tree_model_get (model, iter,
+                      NAME_COLUMN, &name,
+                      -1);
+
+  visible = name && strstr (name, search_text);
+  g_free (name);
+
+  if (visible) {
+    GtkTreeIter parent_iter;
+    GtkTreePath *path;
+
+    gtk_tree_model_iter_parent (model, &parent_iter, iter);
+    path = gtk_tree_model_get_path (model, &parent_iter);
+    gtk_tree_view_expand_row (GTK_TREE_VIEW (dialog->treeview), path, FALSE);
+    gtk_tree_path_free (path);
   }
 
-  gtk_widget_set_sensitive (dialog->clear_button,
-                            dialog->num_checked != 0);
+  return visible;
+}
+
+static void
+clear_data_dialog_dispose (GObject *object)
+{
+  ClearDataDialog *dialog = (ClearDataDialog *)object;
+
+  g_cancellable_cancel (dialog->cancellable);
+  g_clear_object (&dialog->cancellable);
+
+  G_OBJECT_CLASS (clear_data_dialog_parent_class)->dispose (object);
 }
 
 static void
 clear_data_dialog_class_init (ClearDataDialogClass *klass)
 {
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = clear_data_dialog_dispose;
+
+  g_type_ensure (WEBKIT_TYPE_WEBSITE_DATA);
 
   gtk_widget_class_set_template_from_resource (widget_class,
                                                "/org/gnome/epiphany/gtk/clear-data-dialog.ui");
 
-  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, cookies_checkbutton);
-  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, cache_checkbutton);
-  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, passwords_checkbutton);
-  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, history_checkbutton);
   gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, clear_button);
-
-  gtk_widget_class_bind_template_callback (widget_class, checkbutton_toggled_cb);
+  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, treeview);
+  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, treestore);
+  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, treemodelfilter);
+  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, timespan_combo);
+  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, search_entry);
+  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, spinner);
+  gtk_widget_class_bind_template_child (widget_class, ClearDataDialog, stack);
+  gtk_widget_class_bind_template_callback (widget_class, item_toggled_cb);
+  gtk_widget_class_bind_template_callback (widget_class, timespan_combo_changed_cb);
   gtk_widget_class_bind_template_callback (widget_class, clear_data_dialog_response_cb);
+  gtk_widget_class_bind_template_callback (widget_class, search_entry_changed_cb);
 }
 
 static void
@@ -151,6 +430,23 @@ clear_data_dialog_init (ClearDataDialog *dialog)
 {
   gtk_widget_init_template (GTK_WIDGET (dialog));
 
-  dialog->num_checked = 0;
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->cache_checkbutton), TRUE);
+  gtk_tree_model_filter_set_visible_func (dialog->treemodelfilter,
+                                          (GtkTreeModelFilterVisibleFunc)row_visible_func,
+                                          dialog,
+                                          NULL);
+
+  gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->timespan_combo),
+                            dialog->timespan);
+
+  gtk_widget_set_sensitive (dialog->clear_button, FALSE);
+  gtk_spinner_start (dialog->spinner);
+  gtk_stack_set_visible_child_name (dialog->stack, "spinner");
+
+  dialog->cancellable = g_cancellable_new ();
+
+  webkit_website_data_manager_fetch (get_website_data_manger (),
+                                     PERSISTENT_DATA_TYPES,
+                                     dialog->cancellable,
+                                     (GAsyncReadyCallback)website_data_fetched_cb,
+                                     dialog);
 }
diff --git a/src/resources/gtk/clear-data-dialog.ui b/src/resources/gtk/clear-data-dialog.ui
index 82b557e..0030e95 100644
--- a/src/resources/gtk/clear-data-dialog.ui
+++ b/src/resources/gtk/clear-data-dialog.ui
@@ -1,18 +1,35 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <!-- interface-requires gtk+ 3.10 -->
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkTreeStore" id="treestore">
+    <columns>
+      <!-- column-name TYPE -->
+      <column type="guint"/>
+      <!-- column-name ACTIVE -->
+      <column type="gboolean"/>
+      <!-- column-name NAME -->
+      <column type="gchararray"/>
+      <!-- column-name DATA -->
+      <column type="WebKitWebsiteData"/>
+      <!-- column-name SENSITIVE -->
+      <column type="gboolean"/>
+    </columns>
+  </object>
+  <object class="GtkTreeModelFilter" id="treemodelfilter">
+    <property name="child_model">treestore</property>
+  </object>
   <template class="ClearDataDialog" parent="GtkDialog">
-    <property name="border_width">15</property>
+    <property name="height_request">500</property>
     <property name="modal">True</property>
     <property name="window_position">center</property>
     <property name="destroy_with_parent">True</property>
     <property name="type_hint">dialog</property>
-    <property name="resizable">False</property>
     <signal name="response" handler="clear_data_dialog_response_cb"/>
+    <signal name="key-press-event" handler="gtk_search_bar_handle_event" object="search_bar" swapped="true"/>
     <child internal-child="headerbar">
       <object class="GtkHeaderBar">
         <property name="title" translatable="yes">Clear Personal Data</property>
-        <property name="show-close-button">False</property>
+        <property name="show-close-button">True</property>
         <child>
           <object class="GtkButton" id="clear_button">
             <property name="label" translatable="yes">C_lear</property>
@@ -24,46 +41,66 @@
               <class name="text-button"/>
             </style>
           </object>
-          <packing>
-            <property name="pack_type">end</property>
-          </packing>
         </child>
         <child>
-          <object class="GtkButton" id="cancel_button">
-            <property name="label" translatable="yes">_Cancel</property>
+          <object class="GtkToggleButton" id="search_button">
             <property name="visible">True</property>
-            <property name="use_underline">True</property>
             <property name="valign">center</property>
+            <accelerator key="F" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
             <style>
-              <class name="text-button"/>
+              <class name="image-button"/>
             </style>
+            <child internal-child="accessible">
+              <object class="AtkObject">
+                <property name="AtkObject::accessible-name" translatable="yes">Search</property>
+                <property name="AtkObject::accessible-description" translatable="yes">Filter 
domains</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="icon-name">edit-find-symbolic</property>
+                <property name="icon-size">1</property>
+              </object>
+            </child>
           </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
         </child>
       </object>
     </child>
     <child internal-child="vbox">
       <object class="GtkBox">
-        <property name="spacing">12</property>
+        <property name="border_width">0</property>
         <child>
-          <object class="GtkLabel">
+          <object class="GtkSearchBar" id="search_bar">
             <property name="visible">True</property>
-            <property name="halign">start</property>
-            <property name="label" translatable="yes">Select the personal data you wish to clear</property>
-            <attributes>
-              <attribute name="weight" value="bold"/>
-            </attributes>
+            <property name="search-mode-enabled" bind-source="search_button" bind-property="active" 
bind-flags="bidirectional|sync-create"/>
+            <child>
+              <object class="GtkSearchEntry" id="search_entry">
+                <property name="visible">True</property>
+                <property name="width-request">300</property> <!-- looks cool and same as passwords-dialog 
-->
+                <property name="primary_icon_name">edit-find-symbolic</property>
+                <property name="primary_icon_activatable">False</property>
+                <property name="primary_icon_sensitive">False</property>
+                <property name="placeholder_text" translatable="yes">Search domains</property>
+                <signal name="search-changed" handler="search_entry_changed_cb"/>
+              </object>
+            </child>
           </object>
         </child>
         <child>
           <object class="GtkBox">
             <property name="visible">True</property>
             <property name="orientation">vertical</property>
-            <property name="spacing">6</property>
+            <property name="border_width">15</property>
+            <property name="spacing">12</property>
             <child>
               <object class="GtkLabel">
                 <property name="visible">True</property>
                 <property name="halign">start</property>
-                <property name="label" translatable="yes">You are about to clear personal data that is 
stored about the web pages you have visited. Check the types of information that you want to 
remove:</property>
+                <property name="label" translatable="yes">You can select a period of time to clear data for 
all websites modified in that period. If you choose from the beginning of time, then you can also clear data 
only for particular websites.</property>
                 <property name="wrap">True</property>
                 <property name="max_width_chars">50</property>
               </object>
@@ -71,62 +108,138 @@
             <child>
               <object class="GtkBox">
                 <property name="visible">True</property>
-                <property name="margin">10</property>
                 <property name="orientation">vertical</property>
-                <property name="spacing">2</property>
-                <child>
-                  <object class="GtkCheckButton" id="cookies_checkbutton">
-                    <property name="label" translatable="yes">Coo_kies</property>
-                    <property name="visible">True</property>
-                    <property name="use_underline">True</property>
-                    <property name="halign">start</property>
-                    <signal name="toggled" handler="checkbutton_toggled_cb"/>
-                  </object>
-                </child>
+                <property name="spacing">6</property>
                 <child>
-                  <object class="GtkCheckButton" id="cache_checkbutton">
-                    <property name="label" translatable="yes">Cache and _temporary files</property>
+                  <object class="GtkBox">
                     <property name="visible">True</property>
-                    <property name="use_underline">True</property>
-                    <property name="halign">start</property>
-                    <signal name="toggled" handler="checkbutton_toggled_cb"/>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Clear selected personal data 
_from:</property>
+                        <property name="use-underline">True</property>
+                        <property name="mnemonic-widget">timespan_combo</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkComboBoxText" id="timespan_combo">
+                        <property name="visible">True</property>
+                        <signal name="changed" handler="timespan_combo_changed_cb"/>
+                        <items>
+                          <item translatable="yes">the past hour</item>
+                          <item translatable="yes">the past day</item>
+                          <item translatable="yes">the past week</item>
+                          <item translatable="yes">the past four weeks</item>
+                          <item translatable="yes">the beginning of time</item>
+                        </items>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                      </packing>
+                    </child>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkCheckButton" id="history_checkbutton">
-                    <property name="label" translatable="yes">Browsing _history</property>
+                  <object class="GtkStack" id="stack">
                     <property name="visible">True</property>
-                    <property name="use_underline">True</property>
-                    <property name="halign">start</property>
-                    <signal name="toggled" handler="checkbutton_toggled_cb"/>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkCheckButton" id="passwords_checkbutton">
-                    <property name="label" translatable="yes">Saved _passwords</property>
-                    <property name="visible">True</property>
-                    <property name="use_underline">True</property>
-                    <property name="halign">start</property>
-                    <signal name="toggled" handler="checkbutton_toggled_cb"/>
+                    <child>
+                      <object class="GtkSpinner" id="spinner">
+                        <property name="visible">True</property>
+                        <property name="width_request">32</property>
+                        <property name="height_request">32</property>
+                        <property name="halign">center</property>
+                        <property name="valign">center</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                      </object>
+                      <packing>
+                        <property name="name">spinner</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkScrolledWindow">
+                        <property name="visible">True</property>
+                        <property name="expand">True</property>
+                        <child>
+                          <object class="GtkTreeView" id="treeview">
+                            <property name="visible">True</property>
+                            <property name="model">treemodelfilter</property>
+                            <property name="headers-visible">False</property>
+                            <child internal-child="selection">
+                              <object class="GtkTreeSelection">
+                                <property name="mode">none</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkTreeViewColumn" id="active_column">
+                                <child>
+                                  <object class="GtkCellRendererToggle" id="check_renderer">
+                                    <signal name="toggled" handler="item_toggled_cb"/>
+                                  </object>
+                                  <attributes>
+                                    <attribute name="active">1</attribute>
+                                    <attribute name="sensitive">4</attribute>
+                                  </attributes>
+                                </child>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkTreeViewColumn" id="name_column">
+                                <child>
+                                  <object class="GtkCellRendererText"/>
+                                  <attributes>
+                                    <attribute name="text">2</attribute>
+                                    <attribute name="sensitive">4</attribute>
+                                  </attributes>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="name">view</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">center</property>
+                        <property name="valign">center</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="label" translatable="yes">No data found</property>
+                        <attributes>
+                          <attribute name="scale" value="1.4"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="name">nodata</property>
+                      </packing>
+                    </child>
                   </object>
                 </child>
               </object>
             </child>
-          </object>
-        </child>
-        <child>
-          <object class="GtkLabel">
-            <property name="visible">True</property>
-            <property name="halign">start</property>
-            <property name="label" translatable="yes">You cannot undo this action. The data you are choosing 
to clear will be removed forever.</property>
-            <property name="wrap">True</property>
-            <property name="max_width_chars">50</property>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="halign">start</property>
+                <property name="label" translatable="yes">You cannot undo this action. The data you are 
choosing to clear will be removed forever.</property>
+                <property name="wrap">True</property>
+                <property name="max_width_chars">50</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+            </child>
           </object>
         </child>
       </object>
     </child>
     <action-widgets>
-      <action-widget response="-6">cancel_button</action-widget>
       <action-widget response="-5">clear_button</action-widget>
     </action-widgets>
   </template>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]