The "trash" plug-in is almost functional by now
This commit is contained in:
parent
c284de1bf4
commit
373c084c70
@ -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)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user