edi/src/bin/screens/edi_welcome.c

687 lines
22 KiB
C

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <sys/types.h>
#include <pwd.h>
#include <Elementary.h>
#include "edi_screens.h"
#include "edi_config.h"
#include "edi_private.h"
#define _EDI_WELCOME_PROJECT_NEW_TABLE_WIDTH 4
typedef struct _Edi_Skeleton
{
const char *name;
const char *path;
// TODO: add more fields here (taken from skeleton metadata)
} Edi_Skeleton;
static Eina_List *_available_skeletons = NULL;
static Evas_Object *_welcome_window, *_welcome_naviframe;
static Evas_Object *_edi_new_popup;
static Evas_Object *_edi_welcome_list;
static Evas_Object *_edi_project_box;
static Evas_Object *_create_inputs[6];
static Evas_Object *_edi_create_button, *_edi_open_button;
static const char *_edi_message_path;
static void _edi_welcome_add_recent_projects(Evas_Object *);
static void
_edi_on_close_message(void *data,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
evas_object_del(data);
evas_object_del(_edi_new_popup);
}
static void
_edi_on_delete_message(void *data,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
_edi_config_project_remove(_edi_message_path);
evas_object_del(_edi_welcome_list);
_edi_welcome_add_recent_projects(_edi_project_box);
evas_object_del(data);
evas_object_del(_edi_new_popup);
}
static void
_edi_message_open(const char *message, Eina_Bool deletable)
{
Evas_Object *popup, *button;
popup = elm_popup_add(_welcome_window);
_edi_new_popup = popup;
elm_object_part_text_set(popup, "title,text", message);
button = elm_button_add(popup);
elm_object_text_set(button, _("OK"));
elm_object_part_content_set(popup, "button1", button);
evas_object_smart_callback_add(button, "clicked",
_edi_on_close_message, NULL);
if (deletable)
{
button = elm_button_add(popup);
elm_object_text_set(button, _("Delete"));
elm_object_part_content_set(popup, "button2", button);
evas_object_smart_callback_add(button, "clicked",
_edi_on_delete_message, NULL);
}
evas_object_show(popup);
}
static void
_edi_welcome_project_open(const char *path, const unsigned int _edi_creating)
{
if (!edi_open(path) && !_edi_creating)
{
_edi_message_path = path;
_edi_message_open(_("That project directory no longer exists"), EINA_TRUE);
}
else
evas_object_del(_welcome_window);
}
static void
_edi_welcome_project_chosen_cb(void *data,
Evas_Object *obj EINA_UNUSED,
void *event_info)
{
evas_object_del(data);
elm_object_disabled_set(_edi_open_button, EINA_FALSE);
elm_object_disabled_set(_edi_create_button, EINA_FALSE);
if (event_info)
{
_edi_welcome_project_open((const char*)event_info, EINA_FALSE);
}
}
static void
_edi_welcome_choose_exit(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
evas_object_del(data);
elm_object_disabled_set(_edi_open_button, EINA_FALSE);
elm_object_disabled_set(_edi_create_button, EINA_FALSE);
}
static void
_edi_welcome_project_choose_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *win, *fs;
elm_object_disabled_set(_edi_open_button, EINA_TRUE);
elm_object_disabled_set(_edi_create_button, EINA_TRUE);
elm_need_ethumb();
elm_need_efreet();
win = elm_win_util_standard_add("projectselector", _("Choose a Project Folder"));
if (!win) return;
elm_win_focus_highlight_enabled_set(win, EINA_TRUE);
evas_object_smart_callback_add(win, "delete,request", _edi_welcome_choose_exit, win);
fs = elm_fileselector_add(win);
evas_object_size_hint_weight_set(fs, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(fs, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_smart_callback_add(fs, "done", _edi_welcome_project_chosen_cb, win);
elm_win_resize_object_add(win, fs);
evas_object_show(fs);
elm_fileselector_expandable_set(fs, EINA_TRUE);
elm_fileselector_folder_only_set(fs, EINA_TRUE);
elm_fileselector_path_set(fs, eina_environment_home_get());
elm_fileselector_sort_method_set(fs, ELM_FILESELECTOR_SORT_BY_FILENAME_ASC);
evas_object_resize(win, 380 * elm_config_scale_get(), 260 * elm_config_scale_get());
elm_win_center(win, EINA_TRUE, EINA_TRUE);
evas_object_show(win);
}
static void
_edi_welcome_project_new_directory_row_add(const char *text, int row,
Evas_Object *parent)
{
Evas_Object *label, *input;
label = elm_label_add(parent);
elm_object_text_set(label, text);
evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_table_pack(parent, label, 0, row, 1, 1);
evas_object_show(label);
input = elm_fileselector_entry_add(parent);
elm_object_text_set(input, _("Select folder"));
elm_fileselector_folder_only_set(input, EINA_TRUE);
evas_object_size_hint_weight_set(input, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(input, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_table_pack(parent, input, 1, row, _EDI_WELCOME_PROJECT_NEW_TABLE_WIDTH - 1, 1);
evas_object_show(input);
_create_inputs[row] = input;
}
static void
_edi_welcome_project_new_input_row_add(const char *text, const char *placeholder, int row,
Evas_Object *parent)
{
Evas_Object *label, *input;
label = elm_label_add(parent);
elm_object_text_set(label, text);
evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_table_pack(parent, label, 0, row, 1, 1);
evas_object_show(label);
input = elm_entry_add(parent);
elm_entry_scrollable_set(input, EINA_TRUE);
elm_entry_single_line_set(input, EINA_TRUE);
evas_object_size_hint_weight_set(input, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(input, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_table_pack(parent, input, 1, row, _EDI_WELCOME_PROJECT_NEW_TABLE_WIDTH - 1, 1);
evas_object_show(input);
if (placeholder)
{
elm_object_text_set(input, placeholder);
}
_create_inputs[row] = input;
}
static void
_edi_welcome_project_new_create_done_cb(const char *path, Eina_Bool success)
{
if (!success)
{
ERR("Unable to create project at path %s", path);
return;
}
_edi_welcome_project_open(path, EINA_TRUE);
}
static Edi_Skeleton *
_edi_skeleton_new(const char *zippath)
{
Edi_Skeleton *skel;
char *name, *tarname;
skel = malloc(sizeof(Edi_Skeleton));
if (!skel)
return NULL;
skel->path = eina_stringshare_add(zippath);
tarname = ecore_file_strip_ext(ecore_file_file_get(zippath));
name = ecore_file_strip_ext(tarname);
skel->name = eina_stringshare_add(name);
free(tarname);
free(name);
// TODO: here we can search for an (optional) metadata file for the skeleton
// and present more info to the user
return skel;
}
static void
_edi_skeleton_free(Edi_Skeleton *skel)
{
if (skel)
{
eina_stringshare_del(skel->name);
eina_stringshare_del(skel->path);
free(skel);
}
}
static void
_edi_skeletons_discover(const char *path)
{
Eina_List *file_list, *l;
char fullp[PATH_MAX], *p;
file_list = ecore_file_ls(path);
EINA_LIST_FOREACH(file_list, l, p)
{
if (eina_str_has_extension(p, ".tar.gz"))
{
Edi_Skeleton *skel;
snprintf(fullp, sizeof(fullp), "%s/%s", path, p);
skel = _edi_skeleton_new(fullp);
if (skel)
_available_skeletons = eina_list_append(_available_skeletons, skel);
}
free(p);
}
eina_list_free(file_list);
}
static char *
_edi_skeleton_text_get_cb(void *data, Evas_Object *obj EINA_UNUSED,
const char *part EINA_UNUSED)
{
Edi_Skeleton *skel = data;
if (skel && skel->name && skel->name[0])
return strdup(skel->name);
else
return NULL;
}
static void
_edi_skeleton_pressed_cb(void *data EINA_UNUSED, Evas_Object *obj,
void *event_info)
{
Edi_Skeleton *skel = elm_object_item_data_get(event_info);
elm_object_text_set(obj, skel->name);
elm_combobox_hover_end(obj);
}
static void
_edi_welcome_project_new_skeleton_combobox_add(const char *text, int row, Evas_Object *parent)
{
Evas_Object *label, *cmbbox;
Elm_Genlist_Item_Class *itc;
Elm_Object_Item *item;
static char user_skeleton_dir[PATH_MAX];
Edi_Skeleton *skel;
Eina_List *l;
label = elm_label_add(parent);
elm_object_text_set(label, text);
evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_table_pack(parent, label, 0, row, 1, 1);
evas_object_show(label);
cmbbox = elm_combobox_add(parent);
evas_object_size_hint_weight_set(cmbbox, EVAS_HINT_EXPAND, 0);
evas_object_size_hint_align_set(cmbbox, EVAS_HINT_FILL, 0);
elm_object_part_text_set(cmbbox, "guide", _("Select the project type"));
elm_object_text_set(cmbbox, "eflproject");
elm_table_pack(parent, cmbbox, 1, row, _EDI_WELCOME_PROJECT_NEW_TABLE_WIDTH - 1, 1);
evas_object_smart_callback_add(cmbbox, "item,pressed",
_edi_skeleton_pressed_cb, NULL);
evas_object_show(cmbbox);
_create_inputs[row] = cmbbox;
EINA_LIST_FREE(_available_skeletons, skel)
_edi_skeleton_free(skel);
snprintf(user_skeleton_dir, sizeof(user_skeleton_dir),
"%s/skeleton", _edi_config_dir_get());
_edi_skeletons_discover(PACKAGE_DATA_DIR "/skeleton");
_edi_skeletons_discover(user_skeleton_dir);
itc = elm_genlist_item_class_new();
itc->item_style = "default";
itc->func.text_get = _edi_skeleton_text_get_cb;
EINA_LIST_FOREACH(_available_skeletons, l, skel)
{
item = elm_genlist_item_append(cmbbox, itc, skel, NULL,
ELM_GENLIST_ITEM_NONE, NULL, NULL);
if (!strcmp(skel->name, "eflproject"))
elm_genlist_item_selected_set(item, EINA_TRUE);
}
elm_genlist_item_class_free(itc);
}
static void
_edi_welcome_project_new_create_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *entry;
const char *path, *name, *user, *email, *url;
Edi_Skeleton *skeleton;
Elm_Object_Item *item;
item = elm_genlist_selected_item_get(_create_inputs[0]);
skeleton = elm_object_item_data_get(item);
entry = elm_layout_content_get(_create_inputs[1], "elm.swallow.entry");
path = elm_object_text_get(entry);
name = elm_object_text_get(_create_inputs[2]);
url = elm_object_text_get(_create_inputs[3]);
user = elm_object_text_get(_create_inputs[4]);
email = elm_object_text_get(_create_inputs[5]);
if (skeleton && path && path[0] && name && name[0])
edi_create_efl_project(skeleton->path, path, name, url, user, email,
_edi_welcome_project_new_create_done_cb);
// TODO show something to the user in case of missing fields
}
static int
_edi_welcome_user_fullname_get(const char *username, char *fullname, size_t max)
{
struct passwd *p;
char *pos;
unsigned int n;
if (!username)
return -1;
errno = 0;
p = getpwnam(username);
if (p == NULL || max == 0)
{
if (errno == 0)
return 0;
else
return -1;
}
pos = strchr(p->pw_gecos, ',');
if (!pos)
n = strlen(p->pw_gecos);
else
n = pos - p->pw_gecos;
if (n == 0)
return 0;
if (n > max - 1)
n = max - 1;
memcpy(fullname, p->pw_gecos, n);
fullname[n] = '\0';
return 1;
}
static void
_edi_welcome_project_new_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *content, *button, *naviframe = data;
Elm_Object_Item *item;
int row = 0;
char fullname[1024];
char *username;
content = elm_table_add(naviframe);
elm_table_homogeneous_set(content, EINA_TRUE);
evas_object_size_hint_weight_set(content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show(content);
username = getenv("USER");
if (!username)
username = getenv("USERNAME");
_edi_welcome_project_new_skeleton_combobox_add(_("Project Type"), row++, content);
_edi_welcome_project_new_directory_row_add(_("Parent Path"), row++, content);
_edi_welcome_project_new_input_row_add(_("Project Name"), NULL, row++, content);
_edi_welcome_project_new_input_row_add(_("Project URL"), NULL, row++, content);
if (_edi_welcome_user_fullname_get(username, fullname, 1024) > 0)
_edi_welcome_project_new_input_row_add(_("Creator Name"), fullname, row++, content);
else
_edi_welcome_project_new_input_row_add(_("Creator Name"), username, row++, content);
_edi_welcome_project_new_input_row_add(_("Creator Email"), NULL, row++, content);
button = elm_button_add(content);
elm_object_text_set(button, _("Create"));
evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(button, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_show(button);
elm_table_pack(content, button, _EDI_WELCOME_PROJECT_NEW_TABLE_WIDTH - 2, row, 2, 1);
evas_object_smart_callback_add(button, "clicked", _edi_welcome_project_new_create_cb, NULL);
item = elm_naviframe_item_push(naviframe, _("Create New Project"),
NULL, NULL, content, NULL);
elm_naviframe_item_title_enabled_set(item, EINA_TRUE, EINA_TRUE);
}
static void
_edi_welcome_project_clone_click_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *entry;
const char *url, *parent, *name, *dir;
int status;
entry = elm_layout_content_get(_create_inputs[1], "elm.swallow.entry");
parent = elm_object_text_get(entry);
name = elm_object_text_get(_create_inputs[2]);
url = elm_object_text_get(_create_inputs[0]);
dir = edi_path_append(parent, name);
status = edi_scm_git_clone(url, dir);
if (status)
_edi_message_open(_("Unable to clone project, please check URL or try again later"), EINA_TRUE);
else
_edi_welcome_project_open(dir, EINA_FALSE);
}
static void
_edi_welcome_project_clone_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *content, *button, *naviframe = data;
Elm_Object_Item *item;
int row = 0;
content = elm_table_add(naviframe);
elm_table_homogeneous_set(content, EINA_TRUE);
evas_object_size_hint_weight_set(content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show(content);
_edi_welcome_project_new_input_row_add(_("Source Control URL"), NULL, row++, content);
_edi_welcome_project_new_directory_row_add(_("Parent Path"), row++, content);
_edi_welcome_project_new_input_row_add(_("Project Name"), NULL, row++, content);
button = elm_button_add(content);
elm_object_text_set(button, _("Checkout"));
evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(button, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_show(button);
elm_table_pack(content, button, _EDI_WELCOME_PROJECT_NEW_TABLE_WIDTH - 2, row, 2, 1);
evas_object_smart_callback_add(button, "clicked", _edi_welcome_project_clone_click_cb, NULL);
item = elm_naviframe_item_push(naviframe, _("Checkout Existing Project"),
NULL, NULL, content, NULL);
elm_naviframe_item_title_enabled_set(item, EINA_TRUE, EINA_TRUE);
}
static void
_edi_welcome_exit(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
evas_object_del(data);
edi_close();
}
static void
_recent_project_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj,
void *event_info)
{
Evas_Coord w;
Evas_Event_Mouse_Down *ev;
ev = event_info;
evas_object_geometry_get(obj, NULL, NULL, &w, NULL);
if (ev->output.x > w - 20)
{
_edi_config_project_remove((const char *)data);
evas_object_del(_edi_welcome_list);
_edi_welcome_add_recent_projects(_edi_project_box);
}
else
_edi_welcome_project_open((const char *)data, EINA_FALSE);
}
static void
_edi_welcome_add_recent_projects(Evas_Object *box)
{
Evas_Object *list, *label, *ic, *icon_button;
Elm_Object_Item *item;
Eina_List *listitem;
Edi_Config_Project *project;
char *display, *format;
int displen;
list = elm_list_add(box);
_edi_welcome_list = list;
evas_object_size_hint_weight_set(list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(list, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_list_mode_set(list, ELM_LIST_LIMIT);
EINA_LIST_FOREACH(_edi_config->projects, listitem, project)
{
format = "<align=right><color=#ffffff><b>%s: </b></color></align>";
displen = strlen(project->path) + strlen(format) - 1;
display = malloc(sizeof(char) * displen);
snprintf(display, displen, format, project->name);
// Add an 'edit-delete' icon that can be clicked to remove a project directory
icon_button = elm_button_add(box);
ic = elm_icon_add(icon_button);
elm_icon_standard_set(ic, "edit-delete");
elm_image_resizable_set(ic, EINA_FALSE, EINA_TRUE);
label = elm_label_add(box);
elm_object_text_set(label, display);
evas_object_color_set(label, 255, 255, 255, 255);
evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_show(label);
item = elm_list_item_append(list, project->path, label, ic, NULL, project->path);
evas_object_event_callback_add(elm_list_item_object_get(item), EVAS_CALLBACK_MOUSE_DOWN,
_recent_project_mouse_down, project->path);
free(display);
}
elm_object_content_set(box, list);
evas_object_show(list);
}
static Evas_Object *
_edi_welcome_button_create(const char *title, const char *icon_name,
Evas_Object *parent, Evas_Smart_Cb func, void *data)
{
Evas_Object *button, *icon;
button = elm_button_add(parent);
evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0.0);
_edi_create_button = button;
elm_object_text_set(button, title);
icon = elm_icon_add(button);
elm_icon_standard_set(icon, icon_name);
elm_object_part_content_set(button, "icon", icon);
evas_object_smart_callback_add(button, "clicked", func, data);
evas_object_show(button);
return button;
}
Evas_Object *edi_welcome_show()
{
Evas_Object *win, *hbx, *box, *button, *frame, *image, *naviframe;
Elm_Object_Item *item;
char buf[PATH_MAX];
win = elm_win_util_standard_add("main", _("Welcome to Edi"));
if (!win) return NULL;
_welcome_window = win;
elm_win_focus_highlight_enabled_set(win, EINA_TRUE);
evas_object_smart_callback_add(win, "delete,request", _edi_welcome_exit, win);
naviframe = elm_naviframe_add(win);
evas_object_size_hint_weight_set(naviframe, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(win, naviframe);
evas_object_show(naviframe);
_welcome_naviframe = naviframe;
hbx = elm_box_add(naviframe);
elm_box_horizontal_set(hbx, EINA_TRUE);
evas_object_size_hint_weight_set(hbx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show(hbx);
/* Existing projects area */
box = elm_box_add(hbx);
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);
elm_box_pack_end(hbx, box);
evas_object_show(box);
frame = elm_frame_add(box);
elm_object_text_set(frame, _("Recent Projects:"));
evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(box, frame);
evas_object_show(frame);
_edi_project_box = frame;
_edi_welcome_add_recent_projects(frame);
button = _edi_welcome_button_create(_("Open Existing Project"), "folder",
box, _edi_welcome_project_choose_cb, NULL);
elm_box_pack_end(box, button);
/* New project area */
box = elm_box_add(hbx);
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);
elm_box_pack_end(hbx, box);
evas_object_show(box);
snprintf(buf, sizeof(buf), "%s/images/welcome.png", elm_app_data_dir_get());
image = elm_image_add(box);
elm_image_file_set(image, buf, NULL);
evas_object_size_hint_weight_set(image, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(image, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(box, image);
evas_object_show(image);
button = _edi_welcome_button_create(_("Create New Project"), "folder-new",
box, _edi_welcome_project_new_cb, naviframe);
elm_box_pack_end(box, button);
button = _edi_welcome_button_create(_("Checkout Existing Project"), "network-server",
box, _edi_welcome_project_clone_cb, naviframe);
elm_box_pack_end(box, button);
item = elm_naviframe_item_push(naviframe,
_("Choose Project"),
NULL,
NULL,
hbx,
NULL);
elm_naviframe_item_title_enabled_set(item, EINA_FALSE, EINA_FALSE);
evas_object_resize(win, ELM_SCALE_SIZE(480), ELM_SCALE_SIZE(260));
elm_win_center(win, EINA_TRUE, EINA_TRUE);
evas_object_show(win);
return win;
}
Evas_Object *
edi_welcome_create_show()
{
Evas_Object *win;
win = edi_welcome_show();
_edi_welcome_project_new_cb(_welcome_naviframe, NULL, NULL);
return win;
}