1 /*
2  *  Copyright (c) Stephan Arts 2006-2012 <stephan@xfce.org>
3  *
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU General Public License
6  *  as published by the Free Software Foundation; either version 2
7  *  of the License, or (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  *  02110-1301, USA.
18  */
19 
20 #include "util.h"
21 #include "privacy_dialog.h"
22 
23 #include <libxfce4ui/libxfce4ui.h>
24 
25 
26 
27 enum
28 {
29     PROP_0,
30     PROP_FILTER,
31     PROP_LIMIT,
32     PROP_LOCAL_ONLY,
33     PROP_SELECT_MULTIPLE,
34     PROP_RECENT_MANAGER,
35     PROP_SORT_TYPE,
36     PROP_SHOW_TIPS,
37     PROP_SHOW_ICONS,
38     PROP_SHOW_NOT_FOUND,
39     PROP_SHOW_PRIVATE,
40 };
41 
42 
43 
44 static void
45 rstto_recent_chooser_init (GtkRecentChooserIface *iface);
46 
47 static void
48 rstto_privacy_dialog_finalize (GObject *object);
49 static void
50 rstto_privacy_dialog_set_property (GObject *object,
51                                    guint property_id,
52                                    const GValue *value,
53                                    GParamSpec *pspec);
54 static void
55 rstto_privacy_dialog_get_property (GObject *object,
56                                    guint property_id,
57                                    GValue *value,
58                                    GParamSpec *pspec);
59 
60 static void
61 rstto_recent_chooser_add_filter (GtkRecentChooser *chooser,
62                                  GtkRecentFilter *filter);
63 static GList *
64 rstto_recent_chooser_get_items (GtkRecentChooser *chooser);
65 static void
66 cb_rstto_privacy_dialog_combobox_timeframe_changed (GtkComboBox *combobox,
67                                                     gpointer user_data);
68 gboolean
69 cb_rstto_recent_filter_filter_timeframe (const GtkRecentFilterInfo *filter_info,
70                                          gpointer user_data);
71 
72 
73 
74 struct _RsttoPrivacyDialogPrivate
75 {
76     RsttoSettings *settings;
77 
78     GtkWidget *cleanup_frame;
79     GtkWidget *cleanup_vbox;
80     GtkWidget *cleanup_timeframe_combo;
81 
82     GtkRecentManager *recent_manager;
83     GSList           *filters;
84     GtkRecentFilter  *timeframe_filter;
85     time_t            time_now;
86     time_t            time_offset;
87 };
88 
89 
90 
G_DEFINE_TYPE_WITH_CODE(RsttoPrivacyDialog,rstto_privacy_dialog,GTK_TYPE_DIALOG,G_ADD_PRIVATE (RsttoPrivacyDialog)G_IMPLEMENT_INTERFACE (GTK_TYPE_RECENT_CHOOSER,rstto_recent_chooser_init))91 G_DEFINE_TYPE_WITH_CODE (RsttoPrivacyDialog, rstto_privacy_dialog, GTK_TYPE_DIALOG,
92                          G_ADD_PRIVATE (RsttoPrivacyDialog)
93                          G_IMPLEMENT_INTERFACE (GTK_TYPE_RECENT_CHOOSER, rstto_recent_chooser_init))
94 
95 
96 
97 static void
98 rstto_privacy_dialog_init (RsttoPrivacyDialog *dialog)
99 {
100     GtkWidget *display_main_hbox;
101     GtkWidget *display_main_lbl;
102     GtkWidget *button;
103 
104     dialog->priv = rstto_privacy_dialog_get_instance_private (dialog);
105 
106     dialog->priv->settings = rstto_settings_new ();
107     dialog->priv->time_now = time (0);
108     dialog->priv->timeframe_filter = gtk_recent_filter_new ();
109 
110     /* Add recent-filter function to filter in access-time */
111     gtk_recent_filter_add_custom (
112             dialog->priv->timeframe_filter,
113             GTK_RECENT_FILTER_URI,
114             cb_rstto_recent_filter_filter_timeframe,
115             dialog,
116             NULL);
117 
118     display_main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
119     display_main_lbl = gtk_label_new (_("Time range to clear:"));
120 
121     dialog->priv->cleanup_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
122     dialog->priv->cleanup_frame = xfce_gtk_frame_box_new_with_content (_("Cleanup"), dialog->priv->cleanup_vbox);
123     gtk_widget_set_margin_start (dialog->priv->cleanup_frame, 6);
124     dialog->priv->cleanup_timeframe_combo = gtk_combo_box_text_new ();
125     gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (dialog->priv->cleanup_timeframe_combo), 0, _("Last Hour"));
126     gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (dialog->priv->cleanup_timeframe_combo), 1, _("Last Two Hours"));
127     gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (dialog->priv->cleanup_timeframe_combo), 2, _("Last Four Hours"));
128     gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (dialog->priv->cleanup_timeframe_combo), 3, _("Today"));
129     gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (dialog->priv->cleanup_timeframe_combo), 4, _("Everything"));
130     g_signal_connect (dialog->priv->cleanup_timeframe_combo, "changed",
131                       G_CALLBACK (cb_rstto_privacy_dialog_combobox_timeframe_changed), dialog);
132     gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->cleanup_timeframe_combo), 0);
133 
134     gtk_box_pack_start (GTK_BOX (dialog->priv->cleanup_vbox),
135                         display_main_hbox, FALSE, FALSE, 0);
136     gtk_box_pack_start (GTK_BOX (display_main_hbox),
137                         display_main_lbl, FALSE, FALSE, 0);
138     gtk_box_pack_start (GTK_BOX (display_main_hbox),
139                         dialog->priv->cleanup_timeframe_combo, FALSE, FALSE, 0);
140 
141     gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
142                        dialog->priv->cleanup_frame);
143 
144     gtk_widget_show_all (dialog->priv->cleanup_frame);
145 
146     /* Window should not be resizable */
147     gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
148 
149     button = xfce_gtk_button_new_mixed ("gtk-cancel", _("_Cancel"));
150     gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_CANCEL);
151     gtk_widget_show (button);
152     button = xfce_gtk_button_new_mixed ("gtk-apply", _("_Apply"));
153     gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK);
154     gtk_widget_show (button);
155 }
156 
157 static void
rstto_privacy_dialog_class_init(RsttoPrivacyDialogClass * klass)158 rstto_privacy_dialog_class_init (RsttoPrivacyDialogClass *klass)
159 {
160     GObjectClass *object_class = G_OBJECT_CLASS (klass);
161     GParamSpec   *pspec;
162 
163     object_class->finalize = rstto_privacy_dialog_finalize;
164     object_class->set_property = rstto_privacy_dialog_set_property;
165     object_class->get_property = rstto_privacy_dialog_get_property;
166 
167     pspec = g_param_spec_object ("filter",
168                                  "",
169                                  "",
170                                  GTK_TYPE_RECENT_FILTER,
171                                  G_PARAM_READWRITE);
172     g_object_class_install_property (object_class,
173                                      PROP_FILTER,
174                                      pspec);
175     pspec = g_param_spec_object ("recent-manager",
176                                  "",
177                                  "",
178                                  GTK_TYPE_RECENT_MANAGER,
179                                  G_PARAM_READWRITE);
180     g_object_class_install_property (object_class,
181                                      PROP_RECENT_MANAGER,
182                                      pspec);
183     pspec = g_param_spec_int    ("limit",
184                                  "",
185                                  "",
186                                  -1,
187                                  100,
188                                  -1,
189                                  G_PARAM_READWRITE);
190     g_object_class_install_property (object_class,
191                                      PROP_LIMIT,
192                                      pspec);
193     pspec = g_param_spec_boolean ("local-only",
194                                   "",
195                                   "",
196                                   FALSE,
197                                   G_PARAM_READWRITE);
198     g_object_class_install_property (object_class,
199                                      PROP_LOCAL_ONLY,
200                                      pspec);
201 
202     pspec = g_param_spec_boolean ("select-multiple",
203                                   "",
204                                   "",
205                                   FALSE,
206                                   G_PARAM_READWRITE);
207     g_object_class_install_property (object_class,
208                                      PROP_SELECT_MULTIPLE,
209                                      pspec);
210     pspec = g_param_spec_boolean ("show-tips",
211                                   "",
212                                   "",
213                                   FALSE,
214                                   G_PARAM_READWRITE);
215     g_object_class_install_property (object_class,
216                                      PROP_SHOW_TIPS,
217                                      pspec);
218     pspec = g_param_spec_boolean ("show-icons",
219                                   "",
220                                   "",
221                                   FALSE,
222                                   G_PARAM_READWRITE);
223     g_object_class_install_property (object_class,
224                                      PROP_SHOW_ICONS,
225                                      pspec);
226     pspec = g_param_spec_boolean ("show-not-found",
227                                   "",
228                                   "",
229                                   FALSE,
230                                   G_PARAM_READWRITE);
231     g_object_class_install_property (object_class,
232                                      PROP_SHOW_NOT_FOUND,
233                                      pspec);
234     pspec = g_param_spec_boolean ("show-private",
235                                   "",
236                                   "",
237                                   FALSE,
238                                   G_PARAM_READWRITE);
239     g_object_class_install_property (object_class,
240                                      PROP_SHOW_PRIVATE,
241                                      pspec);
242     pspec = g_param_spec_enum   ("sort-type",
243                                  "",
244                                  "",
245                                  GTK_TYPE_RECENT_SORT_TYPE,
246                                  GTK_RECENT_SORT_NONE,
247                                  G_PARAM_READWRITE);
248     g_object_class_install_property (object_class,
249                                      PROP_SORT_TYPE,
250                                      pspec);
251 }
252 
253 static void
rstto_recent_chooser_init(GtkRecentChooserIface * iface)254 rstto_recent_chooser_init (GtkRecentChooserIface *iface)
255 {
256     iface->add_filter = rstto_recent_chooser_add_filter;
257     iface->get_items  = rstto_recent_chooser_get_items;
258 }
259 
260 static void
rstto_privacy_dialog_finalize(GObject * object)261 rstto_privacy_dialog_finalize (GObject *object)
262 {
263     RsttoPrivacyDialog *dialog = RSTTO_PRIVACY_DIALOG (object);
264 
265     if (dialog->priv->settings)
266     {
267         g_object_unref (dialog->priv->settings);
268         dialog->priv->settings = NULL;
269     }
270 
271     if (dialog->priv->filters)
272     {
273         g_slist_free (dialog->priv->filters);
274         dialog->priv->filters = NULL;
275     }
276 
277     G_OBJECT_CLASS (rstto_privacy_dialog_parent_class)->finalize (object);
278 }
279 
280 
281 static void
rstto_privacy_dialog_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)282 rstto_privacy_dialog_set_property (GObject      *object,
283                                    guint         property_id,
284                                    const GValue *value,
285                                    GParamSpec   *pspec)
286 {
287     RsttoPrivacyDialog *dialog = RSTTO_PRIVACY_DIALOG (object);
288 
289     switch (property_id)
290     {
291         case PROP_RECENT_MANAGER:
292             dialog->priv->recent_manager =  g_value_get_object (value);
293             break;
294     }
295 
296 }
297 
298 static void
rstto_privacy_dialog_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)299 rstto_privacy_dialog_get_property (GObject    *object,
300                                    guint       property_id,
301                                    GValue     *value,
302                                    GParamSpec *pspec)
303 {
304 }
305 
306 /******************************************/
307 /* GtkRecentChooserIface static functions */
308 /*                                        */
309 /******************************************/
310 
311 static void
rstto_recent_chooser_add_filter(GtkRecentChooser * chooser,GtkRecentFilter * filter)312 rstto_recent_chooser_add_filter (
313         GtkRecentChooser  *chooser,
314         GtkRecentFilter   *filter)
315 {
316     RsttoPrivacyDialog *dialog = RSTTO_PRIVACY_DIALOG (chooser);
317 
318     /* Add the filter to the list of available filters */
319     dialog->priv->filters =
320             g_slist_append (dialog->priv->filters, filter);
321 }
322 
323 static GList *
rstto_recent_chooser_get_items(GtkRecentChooser * chooser)324 rstto_recent_chooser_get_items (
325         GtkRecentChooser  *chooser)
326 {
327     RsttoPrivacyDialog *dialog = RSTTO_PRIVACY_DIALOG (chooser);
328     GList *all_items = gtk_recent_manager_get_items (dialog->priv->recent_manager);
329     GList *all_items_iter = all_items;
330     GList *items = g_list_copy (all_items);
331     GList *lp;
332     GSList *filters;
333     GtkRecentInfo *info;
334     GtkRecentFilterInfo filter_info;
335     gsize n_applications;
336 
337     for (lp = items; lp != NULL; lp = lp->next)
338         gtk_recent_info_ref (lp->data);
339 
340     while (NULL != all_items_iter)
341     {
342         info = all_items_iter->data;
343 
344         filter_info.contains = GTK_RECENT_FILTER_URI | GTK_RECENT_FILTER_APPLICATION;
345         filter_info.uri = gtk_recent_info_get_uri (info);
346         filter_info.applications = (const gchar **) gtk_recent_info_get_applications (info, &n_applications);
347 
348         if (!gtk_recent_filter_filter (dialog->priv->timeframe_filter, &filter_info))
349         {
350             items = g_list_remove (items, info);
351             gtk_recent_info_unref (info);
352         }
353         else
354         {
355             filters = dialog->priv->filters;
356 
357             while (NULL != filters)
358             {
359                 if (!gtk_recent_filter_filter (filters->data, &filter_info))
360                 {
361                     items = g_list_remove (items, info);
362                     gtk_recent_info_unref (info);
363                     break;
364                 }
365 
366                 filters = g_slist_next (filters);
367             }
368         }
369 
370         g_strfreev ((gchar **) filter_info.applications);
371         all_items_iter = g_list_next (all_items_iter);
372     }
373 
374     g_list_free_full (all_items, (GDestroyNotify) gtk_recent_info_unref);
375 
376     return items;
377 }
378 
379 
380 
381 
382 /***************/
383 /*  CALLBACKS  */
384 /***************/
385 static void
cb_rstto_privacy_dialog_combobox_timeframe_changed(GtkComboBox * combobox,gpointer user_data)386 cb_rstto_privacy_dialog_combobox_timeframe_changed (GtkComboBox *combobox, gpointer user_data)
387 {
388     RsttoPrivacyDialog *dialog = user_data;
389     struct tm *time_info;
390 
391     switch (gtk_combo_box_get_active (combobox))
392     {
393         case 0:
394             dialog->priv->time_offset = 3600;
395             break;
396         case 1:
397             dialog->priv->time_offset = 7200;
398             break;
399         case 2:
400             dialog->priv->time_offset = 14200;
401             break;
402         case 3:
403             /* Convert to localtime */
404             time_info = localtime (&(dialog->priv->time_now));
405 
406             dialog->priv->time_offset = (time_info->tm_hour * 3600) +
407                                         (time_info->tm_min * 60) +
408                                         time_info->tm_sec;
409             break;
410         case 4:
411             dialog->priv->time_offset = dialog->priv->time_now;
412             break;
413     }
414 }
415 
416 gboolean
cb_rstto_recent_filter_filter_timeframe(const GtkRecentFilterInfo * filter_info,gpointer user_data)417 cb_rstto_recent_filter_filter_timeframe (
418         const GtkRecentFilterInfo *filter_info,
419         gpointer user_data)
420 {
421     RsttoPrivacyDialog *dialog = user_data;
422     GtkRecentInfo *info = gtk_recent_manager_lookup_item (dialog->priv->recent_manager, filter_info->uri, NULL);
423     const time_t visited = gtk_recent_info_get_visited (info);
424 
425     gtk_recent_info_unref (info);
426 
427     return (dialog->priv->time_now - visited) < dialog->priv->time_offset;
428 }
429 
430 /********************/
431 /* Public functions */
432 /********************/
433 
434 GtkWidget *
rstto_privacy_dialog_new(GtkWindow * parent,GtkRecentManager * recent_manager)435 rstto_privacy_dialog_new (GtkWindow *parent, GtkRecentManager *recent_manager)
436 {
437     GtkWidget *dialog = g_object_new (RSTTO_TYPE_PRIVACY_DIALOG,
438                                       "title", _("Clear private data"),
439                                       "icon-name", "edit-clear",
440                                       "recent-manager", recent_manager,
441                                       NULL);
442 
443     gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
444 
445     return dialog;
446 }
447