Bundles / src / view /

view_sink.c

/*
 * Copyright (c) 2016 Samsung Electronics Co., Ltd
 *
 * Licensed under the Flora License, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://floralicense.org/license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <app.h>
#include <efl_extension.h>
#include "$(appName).h"
#include "view/view_common.h"
#include "view_defines.h"
#include "view/view_source.h"
#include "view/view_list.h"
#include "view/view_sink.h"

#define FORMAT(type) "%s: "type"<align=right><type>Type: %s</type></align=right>"

typedef struct {
	char *val_1;
	char *val_2;
	bool state;
} list_data_t;

static struct view_info {
	Evas_Object *layout;
	Evas_Object *list;
	Elm_Genlist_Item_Class *itc_title;
	Elm_Genlist_Item_Class *itc_data;
	Elm_Genlist_Item_Class *itc_header;
	Elm_Genlist_Item_Class *itc_header_data;
	Elm_Object_Item *title;

} s_info = {
	.layout = NULL,
	.list = NULL,
	.itc_title = NULL,
	.itc_data = NULL,
	.itc_header = NULL,
	.itc_header_data = NULL,
	.title = NULL,
};

static bool _create_list(void);
static Evas_Object *_item_title_get_cb(void *data, Evas_Object *obj, const char *part);
static Evas_Object *_item_data_get_cb(void *data, Evas_Object *obj, const char *part);
static Evas_Object *_item_header_get_cb(void *data, Evas_Object *obj, const char *part);
static Evas_Object *_item_header_data_get_cb(void *data, Evas_Object *obj, const char *part);
static void _tree_item_expanded(void *data, Evas_Object *obj, void *event_info);
static void _item_delete_cb(void *data, Evas_Object *obj);

/**
 * @brief Function used to create the sink view.
 * @param[in] parent The parent widget
 * @return true on success or false on error.
 */
bool view_sink_create(Evas_Object *parent)
{
	s_info.layout = view_create_layout(parent, EDJ_SINK_FILE_NAME, GROUP_SINK);
	if (!s_info.layout)
		return false;

	if (!_create_list())
		return false;

	return true;
}

/**
 * @brief Returns the sink view's layout widget.
 * @return The layout widget.
 */
Evas_Object *view_sink_get(void)
{
	return s_info.layout;
}

/**
 * @brief Callback function to be used by the data module. Invoked when a new message is received.
 * @param[in] index The index of the new message.
 */
void view_sink_new_message_cb(int index)
{
	dlog_print(DLOG_INFO, LOG_TAG, "[%s:%d] Message received. Index: %d", __FILE__, __LINE__, index);
	s_info.title = view_list_add_item(s_info.list, s_info.itc_title, ELM_GENLIST_ITEM_TREE, NULL, (void*)index, false, ELM_OBJECT_SELECT_MODE_DEFAULT, NULL, NULL);
}

/**
 * @brief Internal function that creates a list object.
 * @return true on success or false on fail.
 */
static bool _create_list(void)
{
	s_info.list = view_list_create(s_info.layout);
	if (!s_info.list) {
		dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] s_info.list == NULL", __FILE__, __LINE__);
		return false;
	}

	s_info.itc_title = view_list_add_itc(_item_title_get_cb, NULL);
	if (!s_info.itc_title) {
		dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] s_info.itc == NULL", __FILE__, __LINE__);
		return false;
	}

	s_info.itc_data = view_list_add_itc(_item_data_get_cb, _item_delete_cb);
	if (!s_info.itc_data) {
		dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] s_info.itc_sub == NULL", __FILE__, __LINE__);
		return false;
	}

	s_info.itc_header = view_list_add_itc(_item_header_get_cb, NULL);
	if (!s_info.itc_header) {
		dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] s_info.itc_sub == NULL", __FILE__, __LINE__);
		return false;
	}

	s_info.itc_header_data = view_list_add_itc(_item_header_data_get_cb, view_list_del_item_cb);
	if (!s_info.itc_header_data) {
		dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] s_info.itc_tree == NULL", __FILE__, __LINE__);
		return false;
	}

	view_list_add_tree_callbacks(s_info.list, s_info.itc_title, s_info.itc_data, _tree_item_expanded, view_common_tree_item_contracted_cb);

	if (!elm_layout_content_set(s_info.layout, PART_LIST, s_info.list)) {
		dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] Failed to set entry as a swallow %s", __FILE__, __LINE__, PART_LIST);
		return false;
	}

	return true;
}

/**
 * @brief Internal callback function added to an genlist's item class. It is invoked when a title item is realized.
 * @param[in] data The user data.
 * @param[in] obj A genlist object.
 * @param[in] part The part name.
 * @return A new layout to be embedded by the genlist's item.
 */
static Evas_Object *_item_title_get_cb(void *data, Evas_Object *obj, const char *part)
{
	char buf[NAME_MAX] = {0,};
	int index = (int)data;
	int count = data_get_count(index);

	Evas_Object *item_layout = view_create_layout(obj, EDJ_SINK_FILE_NAME, GROUP_TITLE);
	if (!item_layout) {
		dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] item_layout == NULL", __FILE__, __LINE__);
		return NULL;
	}

	snprintf(buf, NAME_MAX, "Bundle items: %d", count);
	elm_layout_text_set(item_layout, PART_ITEM, buf);

	return item_layout;
}

/**
 * @brief Internal callback function added to an genlist's item class. It is invoked when a data item (containing the key, value and type) is realized.
 * @param[in] data The user data.
 * @param[in] obj A genlist object.
 * @param[in] part The part name.
 * @return A new layout to be embedded by the genlist's item.
 */
static Evas_Object *_item_data_get_cb(void *data, Evas_Object *obj, const char *part)
{
	list_data_t *list_data = (list_data_t *)data;
	char buf[NAME_MAX] = {0,};

	Evas_Object *item_layout = view_create_layout(obj, EDJ_SINK_FILE_NAME, GROUP_ITEM);
	if (!item_layout) {
		dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] item_layout == NULL", __FILE__, __LINE__);
		return NULL;
	}

	snprintf(buf, NAME_MAX, "Type: %s", list_data->val_2);
	elm_layout_text_set(item_layout, PART_ITEM_KEY_VAL, list_data->val_1);
	elm_layout_text_set(item_layout, PART_ITEM_TYPE, buf);

	if (list_data->state)
		elm_layout_signal_emit(item_layout, SIGNAL_BUBBLES_HIDE, "");

	return item_layout;
}

/**
 * @brief Internal callback function added to an genlist's item class. It is invoked when a header item is realized.
 * @param[in] data The user data.
 * @param[in] obj A genlist object.
 * @param[in] part The part name.
 * @return A new layout to be embedded by the genlist's item.
 */
static Evas_Object *_item_header_get_cb(void *data, Evas_Object *obj, const char *part)
{
	Evas_Object *item_layout = view_create_layout(obj, EDJ_SINK_FILE_NAME, GROUP_HEADER);
	if (!item_layout) {
		dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] item_layout == NULL", __FILE__, __LINE__);
		return NULL;
	}

	return item_layout;
}

/**
 * @brief Internal callback function added to an genlist's item class. It is invoked when a header data item is realized.
 * @param[in] data The user data.
 * @param[in] obj A genlist object.
 * @param[in] part The part name.
 * @return A new layout to be embedded by the genlist's item.
 */
static Evas_Object *_item_header_data_get_cb(void *data, Evas_Object *obj, const char *part)
{
	char *text = (char *)data;
	char buf[NAME_MAX] = {0,};
	char **tokens = NULL;

	Evas_Object *item_layout = view_create_layout(obj, EDJ_SINK_FILE_NAME, GROUP_HEADER_DATA);
	if (!item_layout) {
		dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] item_layout == NULL", __FILE__, __LINE__);
		return NULL;
	}

	tokens = eina_str_split(text, "\2", 2);
	elm_layout_text_set(item_layout, PART_ITEM_KEY_VAL, tokens[0]);
	snprintf(buf, NAME_MAX, "Type: %s", tokens[1]);
	elm_layout_text_set(item_layout, PART_ITEM_TYPE, buf);
	return item_layout;
}

/**
 * @brief Internal function that adds header and data items to the genlist.
 * @param[in] index The index of a message to use.
 * @param[in] parent The parent item.
 */
static void _add_data_items(int index, Elm_Object_Item *parent)
{
	Eina_List* l;
	char* key;
	list_data_t *data = NULL;
	Eina_List *keys = data_get_keys(index);
	int byte_val;
	char buf[NAME_MAX];
	char *string_val;
	bool state = !data_key_exists(index, BUNDLE_HEADER_KEY); /* If header exists the first item won't display the bubbles */

	EINA_LIST_FOREACH(keys, l, key) {
		if (string_equal(BUNDLE_HEADER_KEY, key)) {
			view_list_add_item(s_info.list, s_info.itc_header, ELM_GENLIST_ITEM_TREE, parent, (void*) index, true, ELM_OBJECT_SELECT_MODE_DEFAULT, NULL, NULL);
			continue;
		} else if (string_equal(BUNDLE_HEADER_DATA_KEY, key)) {
			continue;
		} else if (data_is_byte(index, key)) {
			byte_val = data_get_byte(index, key);
			snprintf(buf, NAME_MAX, "%s: %d", key, byte_val);
		} else {
			string_val = data_get_string(index, key);
			snprintf(buf, NAME_MAX, "%s: %s", key, string_val);
		}

			data = calloc(1, sizeof(list_data_t));
			data->val_1 = strdup(buf);
			data->val_2 = strdup(data_get_type_text(index, key));
			data->state = state;

			view_list_add_item(s_info.list, s_info.itc_data, ELM_GENLIST_ITEM_NONE, parent, (void*)data, false, ELM_OBJECT_SELECT_MODE_NONE, NULL, NULL);
			state = false;
	}

	EINA_LIST_FREE(keys, key)
		free(key);
}

/**
 * @brief Internal function that adds header data items.
 * @param[in] index The index of a message to use.
 * @param[in] parent The parent item.
 */
static void _add_header_items(int index, Elm_Object_Item *parent)
{
	int len = 0;
	int i;
	const char **keys = data_get_string_array(index, BUNDLE_HEADER_DATA_KEY, &len);

	for (i = 0; i < len; i++)
		view_list_add_item(s_info.list, s_info.itc_header_data, ELM_GENLIST_ITEM_NONE, parent, (void*)strdup(keys[i]), false, ELM_OBJECT_SELECT_MODE_NONE, NULL, NULL);
}

/**
 * @brief Internal callback function invoked when a TREE item is expanded
 * @param[in] data The use data.
 * @param[in] obj The genlist.
 * @param[in] event_info The expanded item.
 */
static void _tree_item_expanded(void *data, Evas_Object *obj, void *event_info)
{
	Elm_Object_Item *parent = (Elm_Object_Item *)event_info;
	int index = (int)elm_object_item_data_get(parent);
	Evas_Object *header = elm_object_item_part_content_get(parent, "elm.swallow.content");

	elm_layout_signal_emit(header, SIGNAL_ARROW_STATE_CHANGE, "");

	if (elm_genlist_item_item_class_get(parent) == s_info.itc_title)
		_add_data_items(index, parent);
	else if (elm_genlist_item_item_class_get(parent) == s_info.itc_header)
		_add_header_items(index, parent);
}

/**
 * @brief Internal callback function invoked when a data item is removed.
 * @param[in] data The user data.
 * @param[in] obj The genlist.
 */
static void _item_delete_cb(void *data, Evas_Object *obj)
{
	list_data_t *it_data = (list_data_t *)data;

	if (!it_data)
		return;

	free(it_data->val_1);
	free(it_data->val_2);
	free(it_data);
}