The "trash" plug-in is almost functional by now

This commit is contained in:
Pierre Pronchery 2014-01-09 19:04:54 -06:00
parent c284de1bf4
commit 373c084c70

View File

@ -66,6 +66,7 @@
typedef enum _TrashColumn typedef enum _TrashColumn
{ {
TC_PIXBUF = 0, TC_PIXBUF = 0,
TC_FILENAME,
TC_PATH, TC_PATH,
TC_PATH_ORIGINAL, TC_PATH_ORIGINAL,
TC_DELETED, TC_DELETED,
@ -92,14 +93,21 @@ typedef struct _BrowserPlugin
/* prototypes */ /* prototypes */
/* plug-in */
static Trash * _trash_init(BrowserPluginHelper * helper); static Trash * _trash_init(BrowserPluginHelper * helper);
static void _trash_destroy(Trash * trash); static void _trash_destroy(Trash * trash);
static GtkWidget * _trash_get_widget(Trash * trash); static GtkWidget * _trash_get_widget(Trash * trash);
static void _trash_refresh(Trash * trash, GList * selection); static void _trash_refresh(Trash * trash, GList * selection);
/* useful */
static gboolean _trash_confirm(Trash * trash, char const * message);
static int _trash_delete_selection(Trash * trash);
static void _trash_list(Trash * trash); static void _trash_list(Trash * trash);
static int _trash_restore_selection(Trash * trash);
/* callbacks */ /* callbacks */
static void _trash_on_delete(gpointer data);
static void _trash_on_restore(gpointer data);
static void _trash_on_select_all(gpointer data); static void _trash_on_select_all(gpointer data);
static void _trash_on_selection_changed(GtkTreeSelection * treesel, static void _trash_on_selection_changed(GtkTreeSelection * treesel,
gpointer data); gpointer data);
@ -160,19 +168,21 @@ static Trash * _trash_init(BrowserPluginHelper * helper)
gtk_toolbar_insert(GTK_TOOLBAR(widget), toolitem, -1); gtk_toolbar_insert(GTK_TOOLBAR(widget), toolitem, -1);
/* restore */ /* restore */
trash->tb_restore = gtk_tool_button_new_from_stock(GTK_STOCK_UNDO); trash->tb_restore = gtk_tool_button_new_from_stock(GTK_STOCK_UNDO);
/* FIXME handle the signal */ g_signal_connect_swapped(trash->tb_restore, "clicked", G_CALLBACK(
_trash_on_restore), trash);
gtk_toolbar_insert(GTK_TOOLBAR(widget), trash->tb_restore, -1); gtk_toolbar_insert(GTK_TOOLBAR(widget), trash->tb_restore, -1);
/* delete */ /* delete */
trash->tb_delete = gtk_tool_button_new_from_stock(GTK_STOCK_DELETE); trash->tb_delete = gtk_tool_button_new_from_stock(GTK_STOCK_DELETE);
/* FIXME handle the signal */ g_signal_connect_swapped(trash->tb_delete, "clicked", G_CALLBACK(
_trash_on_delete), trash);
gtk_toolbar_insert(GTK_TOOLBAR(widget), trash->tb_delete, -1); gtk_toolbar_insert(GTK_TOOLBAR(widget), trash->tb_delete, -1);
gtk_box_pack_start(GTK_BOX(trash->widget), widget, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(trash->widget), widget, FALSE, TRUE, 0);
widget = gtk_scrolled_window_new(NULL, NULL); widget = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
trash->store = gtk_list_store_new(TC_COUNT, GDK_TYPE_PIXBUF, trash->store = gtk_list_store_new(TC_COUNT, GDK_TYPE_PIXBUF,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_BOOLEAN); G_TYPE_UINT, G_TYPE_STRING, G_TYPE_BOOLEAN);
trash->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL( trash->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(
trash->store)); trash->store));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(trash->view), TRUE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(trash->view), TRUE);
@ -242,30 +252,101 @@ static void _trash_refresh(Trash * trash, GList * selection)
} }
/* useful */
/* trash_confirm */
static gboolean _trash_confirm(Trash * trash, char const * message)
{
GtkWidget * dialog;
int res;
/* XXX move to BrowserPluginHelper */
dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_QUESTION,
GTK_BUTTONS_NONE,
#if GTK_CHECK_VERSION(2, 6, 0)
"%s", _("Question"));
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
#endif
"%s", message);
gtk_dialog_add_buttons(GTK_DIALOG(dialog),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT, NULL);
gtk_window_set_title(GTK_WINDOW(dialog), _("Question"));
res = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return (res == GTK_RESPONSE_ACCEPT) ? 1 : 0;
}
/* trash_delete_selection */
static int _delete_path(Trash * trash, GtkTreeModel * model,
GtkTreePath * path);
static int _trash_delete_selection(Trash * trash)
{
int ret = 0;
GtkTreeSelection * treesel;
GtkTreeModel * model;
GList * rows;
GList * l;
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(trash->view));
if((rows = gtk_tree_selection_get_selected_rows(treesel, &model))
== NULL)
/* nothing is selected */
return 0;
for(l = rows; l != NULL; l = l->next)
ret |= _delete_path(trash, model, l->data);
g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
g_list_free(rows);
_trash_list(trash);
return (ret == 0) ? 0 : -1;
}
static int _delete_path(Trash * trash, GtkTreeModel * model, GtkTreePath * path)
{
int ret = -1;
const char ext[] = DATA_EXTENSION;
GtkTreeIter iter;
gchar * filename;
gchar * p;
size_t len;
if(gtk_tree_model_get_iter(model, &iter, path) != TRUE)
/* XXX report error */
return -1;
gtk_tree_model_get(model, &iter, TC_FILENAME, &filename, TC_PATH, &p,
-1);
if(filename != NULL && (len = strlen(filename)) > sizeof(ext))
filename[len - sizeof(ext) + 1] = '\0';
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() \"%s\" \"%s\"\n", __func__, p, filename);
#endif
/* FIXME implement */
#if 0
ret = unlink(path);
#endif
g_free(filename);
g_free(p);
return ret;
}
/* trash_list */ /* trash_list */
static void _list_add(Trash * trash, Config * config, char const * path,
char const * filename, const time_t sixmonths);
static void _list_get_iter(Trash * trash, GtkTreeIter * iter,
char const * path);
static char * _list_path(void); static char * _list_path(void);
static void _list_purge(Trash * trash); static void _list_purge(Trash * trash);
static void _list_reset(Trash * trash); static void _list_reset(Trash * trash);
static void _trash_list(Trash * trash) static void _trash_list(Trash * trash)
{ {
const char ext[] = DATA_EXTENSION;
const char section[] = DATA_SECTION;
BrowserPluginHelper * helper = trash->helper;
Config * config; Config * config;
char * path; char * path;
DIR * dir; DIR * dir;
struct dirent * de; struct dirent * de;
size_t len;
GtkTreeIter iter;
GdkPixbuf * pixbuf;
char * p;
char const * q;
struct tm tm;
time_t t;
char const * u;
time_t sixmonths; time_t sixmonths;
char buf[16];
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__); fprintf(stderr, "DEBUG: %s()\n", __func__);
@ -285,52 +366,84 @@ static void _trash_list(Trash * trash)
free(path); free(path);
return; return;
} }
sixmonths = time(NULL) - 15552000;
/* FIXME refresh only if necessary */ /* FIXME refresh only if necessary */
_list_reset(trash); _list_reset(trash);
sixmonths = time(NULL) - 15552000;
while((de = readdir(dir)) != NULL) while((de = readdir(dir)) != NULL)
{ _list_add(trash, config, path, de->d_name, sixmonths);
if((len = strlen(de->d_name)) <= sizeof(ext))
continue;
if(strncmp(&de->d_name[len - sizeof(ext) + 1], ext,
sizeof(ext)) != 0)
continue;
config_reset(config);
p = g_strdup_printf("%s/%s", path, de->d_name);
if(config_load(config, p) != 0
|| (q = config_get(config, section, DATA_PATH))
== NULL)
{
g_free(p);
continue;
}
pixbuf = helper->get_icon(helper->browser, q, NULL, NULL, NULL,
24);
t = -1;
if((u = config_get(config, section, DATA_DELETIONDATE)) != NULL
&& strptime(u, "%Y-%m-%dT%H:%M:%S", &tm)
!= NULL)
{
t = mktime(&tm);
len = strftime(buf, sizeof(buf), (t < sixmonths)
? "%b %e %H:%M" : "%b %e %Y", &tm);
buf[len] = '\0';
u = buf;
}
else
u = "";
gtk_list_store_append(trash->store, &iter);
gtk_list_store_set(trash->store, &iter, TC_PIXBUF, pixbuf,
TC_PATH, p, TC_PATH_ORIGINAL, q, TC_DELETED, t,
TC_DELETED_DISPLAY, u, TC_UPDATED, TRUE, -1);
g_free(p);
}
closedir(dir); closedir(dir);
_list_purge(trash); _list_purge(trash);
config_delete(config); config_delete(config);
free(path); free(path);
} }
static void _list_add(Trash * trash, Config * config, char const * path,
char const * filename, const time_t sixmonths)
{
const char ext[] = DATA_EXTENSION;
const char section[] = DATA_SECTION;
BrowserPluginHelper * helper = trash->helper;
size_t len;
GtkTreeIter iter;
GdkPixbuf * pixbuf;
char * p;
char const * q;
struct tm tm;
time_t t = -1;
char const * u;
char buf[16];
if((len = strlen(filename)) <= sizeof(ext))
return;
if(strncmp(&filename[len - sizeof(ext) + 1], ext, sizeof(ext)) != 0)
return;
config_reset(config);
p = g_strdup_printf("%s/%s", path, filename);
if(config_load(config, p) != 0
|| (q = config_get(config, section, DATA_PATH)) == NULL)
{
g_free(p);
return;
}
pixbuf = helper->get_icon(helper->browser, q, NULL, NULL, NULL, 24);
if((u = config_get(config, section, DATA_DELETIONDATE)) != NULL
&& strptime(u, "%Y-%m-%dT%H:%M:%S", &tm) != NULL)
{
t = mktime(&tm);
len = strftime(buf, sizeof(buf), (t >= sixmonths)
? "%b %e %H:%M" : "%b %e %Y", &tm);
buf[len] = '\0';
u = buf;
}
else
u = "";
_list_get_iter(trash, &iter, p);
gtk_list_store_set(trash->store, &iter, TC_PIXBUF, pixbuf,
TC_FILENAME, filename, TC_PATH, p,
TC_PATH_ORIGINAL, q, TC_DELETED, t,
TC_DELETED_DISPLAY, u, TC_UPDATED, TRUE, -1);
g_free(p);
}
static void _list_get_iter(Trash * trash, GtkTreeIter * iter, char const * path)
{
GtkTreeModel * model = GTK_TREE_MODEL(trash->store);
gboolean valid;
gchar * p;
int res;
for(valid = gtk_tree_model_get_iter_first(model, iter); valid == TRUE;
valid = gtk_tree_model_iter_next(model, iter))
{
gtk_tree_model_get(model, iter, TC_PATH, &p, -1);
res = strcmp(path, p);
g_free(p);
if(res == 0)
return;
}
gtk_list_store_append(trash->store, iter);
}
static char * _list_path(void) static char * _list_path(void)
{ {
const char fallback[] = ".local/share"; const char fallback[] = ".local/share";
@ -376,7 +489,71 @@ static void _list_reset(Trash * trash)
} }
/* trash_restore_selection */
static int _restore_path(Trash * trash, GtkTreeModel * model,
GtkTreePath * path);
static int _trash_restore_selection(Trash * trash)
{
/* FIXME code duplicated from _trash_delete_selection() */
int ret = 0;
GtkTreeSelection * treesel;
GtkTreeModel * model;
GList * rows;
GList * l;
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(trash->view));
if((rows = gtk_tree_selection_get_selected_rows(treesel, &model))
== NULL)
/* nothing is selected */
return 0;
for(l = rows; l != NULL; l = l->next)
ret |= _restore_path(trash, model, l->data);
g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
g_list_free(rows);
_trash_list(trash);
return (ret == 0) ? 0 : -1;
}
static int _restore_path(Trash * trash, GtkTreeModel * model,
GtkTreePath * path)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
/* FIXME implement */
return -1;
}
/* callbacks */ /* callbacks */
/* trash_on_delete */
static void _trash_on_delete(gpointer data)
{
Trash * trash = data;
GtkTreeSelection * treesel;
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(trash->view));
if(gtk_tree_selection_count_selected_rows(treesel) > 0
&& _trash_confirm(trash,
_("This will delete the file(s) selected.\n"
"Do you really want to proceed?")))
_trash_delete_selection(trash);
}
/* trash_on_restore */
static void _trash_on_restore(gpointer data)
{
Trash * trash = data;
GtkTreeSelection * treesel;
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(trash->view));
if(gtk_tree_selection_count_selected_rows(treesel) > 0)
_trash_restore_selection(trash);
}
/* trash_on_select_all */ /* trash_on_select_all */
static void _trash_on_select_all(gpointer data) static void _trash_on_select_all(gpointer data)
{ {