654 lines
16 KiB
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;
|
|
}
|
|
|