directory_view.c 6.47 KB
Newer Older
Nicolas Pomepuy's avatar
Nicolas Pomepuy committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*****************************************************************************
 * Copyright © 2015 VideoLAN, VideoLabs SAS
 *****************************************************************************
 *
 * Authors: Nicolas Rechatin [nicolas@videolabs.io]
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
/*
 * By committing to this project, you allow VideoLAN and VideoLabs to relicense
 * the code to a different OSI approved license, in case it is required for
 * compatibility with the Store
 *****************************************************************************/

#include "common.h"

29
#include <Elementary.h>
30 31 32
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
33

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
34
#include "directory_view.h"
35
#include "ui/interface.h"
36
#include "ui/utils.h"
Nicolas Pomepuy's avatar
Nicolas Pomepuy committed
37 38 39 40

void
list_selected_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
{
41
    directory_data *dd = data;
Nicolas Pomepuy's avatar
Nicolas Pomepuy committed
42

43
    if (dd->is_file)
44 45
    {
        /* Start the playback of the given file */
46
        intf_create_video_player(dd->dv->p_intf, dd->file_path);
Thomas Guillem's avatar
Thomas Guillem committed
47
    }
48
    else
Thomas Guillem's avatar
Thomas Guillem committed
49 50
    {
        /* Continue to browse media folder */
51
        browse(dd->dv, dd->file_path);
Thomas Guillem's avatar
Thomas Guillem committed
52
    }
Nicolas Pomepuy's avatar
Nicolas Pomepuy committed
53 54 55 56 57
}

static void
free_list_item_data(void *data, Evas_Object *obj, void *event_info)
{
58
    directory_data *dd = data;
Thomas Guillem's avatar
Thomas Guillem committed
59 60 61
    /* Free the file path when the current list is deleted */
    /* For example when the player is launched or a new list is created */
    free(dd->file_path);
Ludovic Fauvet's avatar
Ludovic Fauvet committed
62
    free(dd);
Nicolas Pomepuy's avatar
Nicolas Pomepuy committed
63 64
}

65 66 67 68 69
static int compare_sort_items(const void *data1, const void *data2)
{
	const char *label1, *label2;
	const Elm_Object_Item *li_it1 = data1;
	const Elm_Object_Item *li_it2 = data2;
70
	const directory_data *li_data1, *li_data2;
71 72 73 74

	label1 = elm_object_item_text_get(li_it1);
	label2 = elm_object_item_text_get(li_it2);

75 76 77
	li_data1 = elm_object_item_data_get(data1);
	li_data2 = elm_object_item_data_get(data2);

78
	if (!li_data1->is_file && li_data2->is_file)
79
		return -1;
80
	else if (li_data1->is_file && !li_data2->is_file)
81 82
		return 1;

83 84 85
	return strcasecmp(label1, label2);
}

Nicolas Pomepuy's avatar
Nicolas Pomepuy committed
86
Evas_Object*
87
browse(directory_view *dv, const char* path)
Nicolas Pomepuy's avatar
Nicolas Pomepuy committed
88
{
89
    Elm_Object_Item *item;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
90 91
    Evas_Object *file_list;
    directory_data *dd;
Thomas Guillem's avatar
Thomas Guillem committed
92 93
    DIR* rep = NULL;
    struct dirent* current_folder = NULL;
94 95
    struct stat st;
    char tmppath[PATH_MAX];
Ludovic Fauvet's avatar
Ludovic Fauvet committed
96
    char *cpath;
97
    bool is_file;
Thomas Guillem's avatar
Thomas Guillem committed
98 99

    /* Make a realpath to use a clean path in the function */
100
    cpath = realpath(path, NULL);
Thomas Guillem's avatar
Thomas Guillem committed
101

102
    if (cpath == NULL)
Thomas Guillem's avatar
Thomas Guillem committed
103
    {
Thomas Guillem's avatar
Thomas Guillem committed
104
        LOGI("No path");
Thomas Guillem's avatar
Thomas Guillem committed
105 106 107
        return NULL ;
    }

108
    /* Open the path repository then put it as a dirent variable */
109
    rep = opendir(cpath);
110

Thomas Guillem's avatar
Thomas Guillem committed
111 112 113 114
    if  (rep == NULL)
    {
        char *error;
        error = strerror(errno);
Thomas Guillem's avatar
Thomas Guillem committed
115
        LOGI("Empty repository or Error due to %s", error);
Thomas Guillem's avatar
Thomas Guillem committed
116

117 118 119 120 121 122 123 124 125 126 127
        if (strcmp(cpath, "/") == 0)
        {
            /* We're already on the root directory don't open the parent directory */
            free(cpath);
            return NULL;
        }

        free(cpath);

        /* Try to open the parent directory */
        sprintf(tmppath, "%s/..", path);
128
        return browse(dv, tmppath);
Thomas Guillem's avatar
Thomas Guillem committed
129 130
    }

131
    /* Create the box container */
132
    Evas_Object *box = elm_box_add(dv->p_parent);
133 134 135 136
    evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_show(box);

137
    /* Create the current directory label */
138
    Evas_Object *directory =  elm_label_add(dv->p_parent);
139
    elm_object_text_set(directory, cpath);
140 141 142
    elm_box_pack_end(box, directory);
    evas_object_show(directory);

143
    /* Create the list */
144
    file_list = elm_list_add(dv->p_parent);
Thomas Guillem's avatar
Thomas Guillem committed
145

146
    /* Browse the current directory */
Thomas Guillem's avatar
Thomas Guillem committed
147 148
    while ((current_folder = readdir(rep)) != NULL)
    {
149 150
        if (!current_folder->d_name)
            continue;
Thomas Guillem's avatar
Thomas Guillem committed
151 152

        /* Avoid genlist item append for "." and ".." d_name */
153
	    if (strcmp(current_folder->d_name, ".") == 0 || strcmp(current_folder->d_name, "..") == 0)
Thomas Guillem's avatar
Thomas Guillem committed
154 155 156 157
        {
            continue;
        }

158 159 160 161 162 163 164
        /* Concatenate the file path and the selected folder or file name */
        sprintf(tmppath, "%s/%s", cpath, current_folder->d_name);

        if (stat(tmppath, &st) != 0)
            continue;

        if (S_ISREG(st.st_mode))
165
            is_file = true;
166
        else if (S_ISDIR(st.st_mode))
167
            is_file = false;
168 169 170 171
        else
            continue;

        dd = malloc(sizeof(*dd));
172
        dd->dv = dv;
173
        dd->is_file = is_file;
174 175
        dd->file_path = strdup(tmppath);

Thomas Guillem's avatar
Thomas Guillem committed
176
        /* Set and append new item in the list */
177
        item = elm_list_item_sorted_insert(file_list, current_folder->d_name, NULL, NULL, list_selected_cb, dd, compare_sort_items);
178

Thomas Guillem's avatar
Thomas Guillem committed
179 180 181
        /* */
        elm_object_item_del_cb_set(item, free_list_item_data);
    }
182 183
    closedir(rep);

184 185 186 187 188 189 190 191
    /* Prepend the '..' item */
    dd = malloc(sizeof(*dd));
    dd->dv = dv;
    dd->is_file = false;
    asprintf(&dd->file_path, "%s/..", cpath);
    item = elm_list_item_prepend(file_list, "..", NULL, NULL, list_selected_cb, dd);
    elm_object_item_del_cb_set(item, free_list_item_data);

192 193 194 195 196 197 198
    elm_list_go(file_list);

    elm_box_pack_end(box, file_list);
    evas_object_size_hint_weight_set(file_list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    /* The next line is required or the list won't show up */
    evas_object_size_hint_align_set(file_list, EVAS_HINT_FILL, EVAS_HINT_FILL);

Thomas Guillem's avatar
Thomas Guillem committed
199
    evas_object_show(file_list);
200

201
    elm_object_content_set(dv->p_parent, box);
202
    free(cpath);
Thomas Guillem's avatar
Thomas Guillem committed
203

204
    return box;
Nicolas Pomepuy's avatar
Nicolas Pomepuy committed
205
}
206

207
interface_view*
208
create_directory_view(interface *intf, Evas_Object *parent)
209
{
210 211
    interface_view *view = calloc(1, sizeof(*view));

212 213 214
    directory_view *dv = malloc(sizeof(*dv));
    dv->p_intf = intf;
    dv->p_parent = parent;
215 216

    //view->p_view_sys = dv;
217

218
    const char *psz_path = application_get_media_path(intf_get_application(intf), MEDIA_DIRECTORY);
219 220
    view->view = browse(dv, psz_path);
    return view;
221
}