enlightenment/src/bin/e_fileman_mime.c

654 lines
16 KiB
C

/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
/* e_fileman_mime.c
* ================
* will provide basic function for mime types, mime handlers
* and operations with them, also a small app to actually
* edit the mime database
*
*
* abstract types
* ==============================
* the abstract types will be in a hierarchy way, all the leafs will heritate the parents
* info (actions: run,open,edit,whatever)
*
* properties:
* mime: each leaf might have a mime type associated to it ? it wouldnt be neccesary for now,
* efm will handle only file names, in the future might visulize other file types?
*
*
* file
* +---- data
* +---- image
* +---- jpg
* :mime image/jpeg
* +---- png
* +---- audio
* +---- mp3
* +---- ogg
* +---- wav
* +---- directory
* +---- special
* +---- executable
* +---- a.out
* +---- java class
* +---- scripts
*
*
*
* file recognition for above types
* ================================
* 1. by regex
* 2. by suffix
* 3. by type (directory,hidden,etc)
* 4. properties (fifo,socket,executables,etc)
*
* icons visuals
* =============
* 1. by properties (read,write,execute)
* 2. user defined (video directory, audo directory)
* 3. by file contents (if a dir is full of mp3, might be an audio dir)
*
*
* previews and thumbnails
* =======================
* a thumbnail can be done for example on images,videos,or any graphical file
* but a preview is for example that when you are over an audio file it starts playing
*
* actions
* =======
* each mime entry will have a list of possible actions to be taken for it
* to define the command to execute there are several tokens like:
*
* %f => file input
* %h => hover file (might be the current directory, other file, whatever)
*
*
* FUTURE
* ======
* a new approach can be made, but is too expensive for what e17 currently needs.
* the mime subsystem can be in fact independent from e_fileman_smart (the function calls
* are very simple to change, just pass always an Evas_List of files, and the E_Fm_File hover,
* instead of the E_Fileman_Smart). What is complicated is how to pass the data to the internal
* actions, and if we should define the internal actions here or in the component that will
* use the mime subsytem.
*
*/
#include "e.h"
static E_Fm_Mime_Entry *_e_fm_mime_common(E_Fm_Mime_Entry *e1, E_Fm_Mime_Entry *e2);
static char *_e_fm_mime_suffix_get(char *filename);
static void _e_fm_mime_action_append(E_Fm_Mime_Entry *entry, char *action_name);
static void _e_fm_mime_action_default_set(E_Fm_Mime_Entry *entry, char *action_name);
static char *_e_fm_mime_string_tokenizer(Evas_List *files, E_Fm_File *dir, char *istr);
/* definitions of the internal actions */
static void _e_fm_mime_action_internal_folder_open(E_Fm_Smart_Data *data);
static void _e_fm_mime_action_internal_folder_open_other(E_Fm_Smart_Data *data);
static void _e_fm_mime_action_internal_copy_to(E_Fm_Smart_Data *data);
static void _e_fm_mime_action_internal_move_to(E_Fm_Smart_Data *data);
/* definitions of thumbnail functions */
Evas_Object * _e_fm_mime_thumbnail_evas(char *path, Evas_Coord w, Evas_Coord h, Evas *evas, Evas_Object **tmp, void (*cb)(Evas_Object *obj, void *data), void *data);
static int init_count = 0;
static Evas_List *entries = NULL;
static Evas_List *actions = NULL;
/* returns the saved mime tree or a default one */
int
e_fm_mime_init(void)
{
E_Fm_Mime_Entry *root;
E_Fm_Mime_Entry *entry;
E_Fm_Mime_Entry *l1,*l2;
E_Fm_Mime_Action *action;
if(init_count)
return 1;
/* internal actions */
/********************/
action = E_NEW(E_Fm_Mime_Action,1);
action->name = strdup("_folder_open");
action->label = strdup("Open the Folder");
action->is_internal = 1;
action->internal.function = &_e_fm_mime_action_internal_folder_open;
actions = evas_list_append(actions,action);
action = E_NEW(E_Fm_Mime_Action,1);
action->name = strdup("_folder_open_other");
action->label = strdup("Open the Folder in other Window");
action->is_internal = 1;
action->internal.function = &_e_fm_mime_action_internal_folder_open_other;
actions = evas_list_append(actions,action);
action = E_NEW(E_Fm_Mime_Action,1);
action->name = strdup("_copy_to");
action->label = strdup("Copy to %h");
action->relative = 1;
action->is_internal = 1;
action->internal.function = &_e_fm_mime_action_internal_copy_to;
actions = evas_list_append(actions,action);
action = E_NEW(E_Fm_Mime_Action,1);
action->name = strdup("_move_to");
action->label = strdup("Move to %h");
action->relative = 1;
action->is_internal = 1;
action->internal.function = &_e_fm_mime_action_internal_move_to;
actions = evas_list_append(actions,action);
/* actions */
/***********/
action = E_NEW(E_Fm_Mime_Action,1);
action->name = strdup("gimp_edit");
action->label = strdup("Edit with Gimp");
action->cmd = strdup("gimp %f");
action->multiple = 1;
actions = evas_list_append(actions,action);
action = E_NEW(E_Fm_Mime_Action,1);
action->name = strdup("exhibit_view");
action->label = strdup("View with Exhibit");
action->cmd = strdup("exhibit %f");
action->multiple = 0;
actions = evas_list_append(actions,action);
action = E_NEW(E_Fm_Mime_Action,1);
action->name = strdup("xmms_enqueue");
action->label = strdup("Add to XMMS Queue");
action->cmd = strdup("xmms -e %f");
action->multiple = 1;
actions = evas_list_append(actions,action);
action = E_NEW(E_Fm_Mime_Action,1);
action->name = strdup("xmms_play");
action->label = strdup("Play with XMMS");
action->cmd = strdup("xmms %f");
action->multiple = 0;
actions = evas_list_append(actions,action);
/* entries */
/***********/
root = E_NEW(E_Fm_Mime_Entry,1);
root->name = strdup("file");
root->label = strdup("Unkown File");
root->level = 0;
entries = evas_list_append(entries,root);
_e_fm_mime_action_default_set(root, "_copy_to");
_e_fm_mime_action_append(root, "_move_to");
/* data */
entry = E_NEW(E_Fm_Mime_Entry,1);
entry->name = strdup("data");
entry->label = strdup("Data File");
entry->parent = root;
entry->level = 1;
entries = evas_list_append(entries,entry);
l1 = entry;
{
/* image */
entry = E_NEW(E_Fm_Mime_Entry,1);
entry->name = strdup("image");
entry->label = strdup("Image File");
entry->parent = l1;
entry->level = 2;
entries = evas_list_append(entries,entry);
_e_fm_mime_action_default_set(entry, "gimp_edit");
_e_fm_mime_action_append(entry, "exhibit_view");
l2 = entry;
{
/* jpg */
entry = E_NEW(E_Fm_Mime_Entry, 1);
entry->name = strdup("jpg");
entry->label = strdup("JPEG Image");
entry->parent = l2;
entry->level = 3;
entry->suffix = strdup("jpg");
entry->thumbnail = &_e_fm_mime_thumbnail_evas;
entries = evas_list_append(entries,entry);
/* png */
entry = E_NEW(E_Fm_Mime_Entry, 1);
entry->name = strdup("png");
entry->label = strdup("PNG Image");
entry->parent = l2;
entry->level = 3;
entry->suffix = strdup("png");
entry->thumbnail = &_e_fm_mime_thumbnail_evas;
entries = evas_list_append(entries,entry);
}
/* audio */
entry = E_NEW(E_Fm_Mime_Entry,1);
entry->name = strdup("audio");
entry->label = strdup("Audio File");
entry->parent = l1;
entry->level = 2;
entries = evas_list_append(entries,entry);
_e_fm_mime_action_append(entry, "xmms_play");
_e_fm_mime_action_append(entry, "xmms_enqueue");
l2 = entry;
{
/* mp3 */
entry = E_NEW(E_Fm_Mime_Entry, 1);
entry->name = strdup("mp3");
entry->label = strdup("MP3 Audio");
entry->parent = l2;
entry->level = 3;
entry->suffix = strdup("mp3");
entries = evas_list_append(entries,entry);
/* ogg */
entry = E_NEW(E_Fm_Mime_Entry, 1);
entry->name = strdup("ogg");
entry->label = strdup("OGG Audio");
entry->parent = l2;
entry->level = 3;
entry->suffix = strdup("ogg");
entries = evas_list_append(entries,entry);
/* wav */
entry = E_NEW(E_Fm_Mime_Entry, 1);
entry->name = strdup("wav");
entry->label = strdup("WAV Audio");
entry->parent = l2;
entry->level = 3;
entry->suffix = strdup("wav");
entries = evas_list_append(entries,entry);
}
}
/* directory */
entry = E_NEW(E_Fm_Mime_Entry,1);
entry->name = strdup("folder");
entry->label = strdup("Folder");
entry->type = E_FM_FILE_TYPE_DIRECTORY;
entry->parent = root;
entry->level = 1;
entries = evas_list_append(entries,entry);
_e_fm_mime_action_default_set(entry, "_folder_open");
_e_fm_mime_action_append(entry, "_folder_open_other");
l1 = entry;
init_count++;
return 1;
}
void
e_fm_mime_shutdwon(void)
{
init_count--;
}
/* returns the shortest root mime for a list of @files
* FIXME can be implemented faster? delete the list while iterating
*/
E_Fm_Mime_Entry *
e_fm_mime_get_from_list(Evas_List *files)
{
E_Fm_File *file;
E_Fm_Mime_Entry *entry;
Evas_List *l;
if (files == NULL)
return NULL;
file = (E_Fm_File *)files->data;
entry = file->mime;
for (l = files->next; l; l = l->next)
{
E_Fm_Mime_Entry *eme;
file = (E_Fm_File *)l->data;
eme = file->mime;
entry = _e_fm_mime_common(entry,eme);
}
return entry;
}
/* returns the mime entry for a file */
void
e_fm_mime_set(E_Fm_File *file)
{
Evas_List *l;
for(l = entries; l; l = l->next)
{
E_Fm_Mime_Entry *entry;
entry = (E_Fm_Mime_Entry *)l->data;
/* FIXME add all the possible comparision, suffix,regexp,flags,etc */
if(entry->suffix)
{
char *suffix;
suffix = _e_fm_mime_suffix_get(file->name);
if(!suffix)
continue;
if(!strcasecmp(suffix,entry->suffix))
{
//printf("found by suffix %s\n", suffix);
file->mime = entry;
}
free(suffix);
}
if(entry->type)
{
if(entry->type == file->type)
file->mime = entry;
}
}
/* if it doesnt match anything set to the root */
if(!file->mime)
file->mime = (E_Fm_Mime_Entry*)entries->data;
}
#if 0
EAPI E_Fm_Mime_Action *
e_fm_mime_action_get_by_label(char *label)
{
Evas_List *l;
E_Fm_Mime_Action *action = NULL;
for(l = actions; l; l = l->next)
{
action = (E_Fm_Mime_Action*)l->data;
if(!strcmp(label,action->label))
break;
}
return action;
}
#endif
/* will call the command of an @action for the fileman_smart @sd */
EAPI int
e_fm_mime_action_call(E_Fm_Smart_Data *sd, E_Fm_Mime_Action *action)
{
Ecore_Exe *exe;
char *command;
/* FIXME: use the e app execution mechanisms where possible so we can
* collect error output
*/
if(action->is_internal)
{
action->internal.function(sd);
}
else
{
command = _e_fm_mime_string_tokenizer(sd->operation.files,sd->operation.hover,action->cmd);
printf("going to execute %s\n", command);
exe = ecore_exe_run(command, NULL);
if (!exe)
{
e_error_dialog_show(_("Run Error"),
_("Enlightenment was unable to fork a child process:\n"
"\n"
"%s\n"
"\n"),
command);
return 0;
}
}
return 1;
}
EAPI void
e_fm_mime_action_default_call(E_Fm_Smart_Data *sd)
{
E_Fm_Mime_Entry *mime;
E_Fm_Mime_Action *action;
mime = sd->operation.mime;
do
{
action = mime->action_default;
if(!action)
{
mime = mime->parent;
continue;
}
/* if we reach here we have an action */
break;
} while(mime);
if(!action)
return;
e_fm_mime_action_call(sd, action);
}
EAPI char *
e_fm_mime_translate(E_Fm_Smart_Data *sd, char *istr)
{
char *ostr;
ostr = _e_fm_mime_string_tokenizer(sd->operation.files,sd->operation.hover, istr);
return ostr;
}
/* subsystem functions */
/***********************/
/* returns the shortest root for both entries @e1 and @e2
* FIXME can be implemented faster?
*/
static E_Fm_Mime_Entry *
_e_fm_mime_common(E_Fm_Mime_Entry *e1, E_Fm_Mime_Entry *e2)
{
E_Fm_Mime_Entry *tmp;
int i;
int count;
/* take the lowest on the tree */
/* set the e1 upper, e2 lower */
if(e1->level > e2->level)
{
count = e1->level - e2->level;
tmp = e1;
e1 = e2;
e2 = tmp;
}
else
count = e2->level - e1-> level;
/* first equal levels */
for(i = 0; i < count; i++)
{
e2 = e2->parent;
}
/* get up on the tree until we find the same parent */
for(i = e1->level; i >= 0; i--)
{
if(!strcmp(e1->name,e2->name))
return e1;
e1 = e1->parent;
e2 = e2->parent;
}
/* this should never happen */
return NULL;
}
/* will translate %f,%d to file,dir respective */
static char*
_e_fm_mime_string_tokenizer(Evas_List *files, E_Fm_File *hover, char *istr)
{
char *buf;
char *c;
int i, bsize,trans;
Evas_List *l;
buf = calloc(PATH_MAX,sizeof(char));
bsize = PATH_MAX;
i = 0;
trans = 0;
for(c = istr; *c; c++)
{
if( i > bsize - 1)
{
bsize += PATH_MAX;
buf = realloc(buf,bsize);
}
if(trans)
{
char *astr = NULL;
if(*c == 'f')
{
int j = 2;
astr = calloc(PATH_MAX,sizeof(char));
for(l = files; l; l = l->next)
{
E_Fm_File *file;
file = (E_Fm_File *)l->data;
sprintf(astr,"%s %s",astr,file->path);
astr = realloc(astr,PATH_MAX*j);
j++;
}
}
if(*c == 'h')
{
astr = strdup(hover->path);
}
if(!astr)
continue;
if(bsize < i + strlen(astr))
{
bsize += strlen(astr) + 1;
buf = realloc(buf,bsize);
}
buf[i-1] = '\0';
sprintf(buf, "%s%s", buf, astr);
i += strlen(astr) - 1;
trans = 0;
free(astr);
continue;
}
if(*c == '%')
trans = 1;
else
buf[i] = *c;
i++;
}
return buf;
}
static void
_e_fm_mime_action_append(E_Fm_Mime_Entry *entry, char *action_name)
{
Evas_List *l;
for(l = actions; l; l = l->next)
{
E_Fm_Mime_Action *action;
action = (E_Fm_Mime_Action *)l->data;
if(!strcmp(action->name, action_name))
{
entry->actions = evas_list_append(entry->actions, action);
break;
}
}
}
static void
_e_fm_mime_action_default_set(E_Fm_Mime_Entry *entry, char *action_name)
{
Evas_List *l;
for(l = actions; l; l = l->next)
{
E_Fm_Mime_Action *action;
action = (E_Fm_Mime_Action *)l->data;
if(!strcmp(action->name, action_name))
{
/* overwrite the old default action */
if(action->relative)
entry->action_default_relative = action;
else
entry->action_default = action;
entry->actions = evas_list_append(entry->actions, action);
break;
}
}
}
static char *
_e_fm_mime_suffix_get(char *filename)
{
char *suf;
suf = strrchr(filename, '.');
if (suf)
{
suf++;
suf = strdup(suf);
return suf;
}
return NULL;
}
static void
_e_fm_mime_action_internal_folder_open(E_Fm_Smart_Data *sd)
{
E_Fm_File *file;
file = sd->operation.files->data;
if (file) e_fm_dir_set(sd->object, file->path);
}
static void
_e_fm_mime_action_internal_folder_open_other(E_Fm_Smart_Data *sd)
{
E_Fileman *fileman;
E_Fm_File *file;
file = sd->operation.files->data;
if (file)
{
fileman = e_fileman_new_to_dir(e_container_current_get(e_manager_current_get()), file->path);
e_fileman_show(fileman);
}
}
static void
_e_fm_mime_action_internal_copy_to(E_Fm_Smart_Data *sd)
{
printf("going to copy to %s\n", sd->operation.hover->path);
}
static void
_e_fm_mime_action_internal_move_to(E_Fm_Smart_Data *sd)
{
printf("going to move to %s\n", sd->operation.hover->path);
}
/* thumbnail functions */
/***********************/
Evas_Object *
_e_fm_mime_thumbnail_evas(char *path, Evas_Coord w, Evas_Coord h, Evas *evas, Evas_Object **tmp, void (*cb)(Evas_Object *obj, void *data), void *data)
{
Evas_Object *r;
r = e_thumb_icon_add(evas);
e_thumb_icon_file_set(r, path, NULL);
e_thumb_icon_size_set(r, w, h);
e_thumb_icon_begin(r);
return r;
}