Type Definitions

The viewdata_s structure contains references to all component objects created by the View module:

typedef struct
{
// The main window object
Evas_Object* win;
// The conformant object
Evas_Object* conform;
// The main window's layout object (embedded into the conform component)
Evas_Object* layout_main_panel;
// The toolbar object (embedded into the PART_MAIN_TOOLBAR part of
// the layout_main_panel object)
Evas_Object* main_toolbar;
// The data source item of the main_toolbar component
Elm_Object_Item *main_toolbar_item_data_source;
// The data sink item of the main_toolbar component
Elm_Object_Item *main_toolbar_item_data_sink;
// The data source view layout (embedded into the PART_MAIN_CONTENT part
// of the layout_main_panel object)
Evas_Object* layout_data_source;
// The data source edit panel layout (embedded into the PART_MAIN_CONTENT
// part of the layout_main_panel object)
Evas_Object* layout_data_source_edit;
// The key name entry component (embedded into the PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY
// part of the layout_data_source_edit object)
Evas_Object* data_source_key_entry;
// The value entry component (embedded into the PART_DATA_SOURCE_EDIT_PANEL_VALUE_PANEL_ENTRY
// part of the layout_data_source_edit object)
Evas_Object* data_source_value_entry;
// The value type selector component (embedded into the PART_DATA_SOURCE_EDIT_PANEL_TYPE_PANEL_ENTRY
// part of the layout_data_source_edit object)
Evas_Object* data_source_type_selector;
// The data source list panel layout (embedded into the PART_DATA_SOURCE_LIST_PANEL
// part of the layout_data_source object)
Evas_Object* layout_data_source_list;
// The header inclusion check component (embedded into the PART_DATA_SOURCE_LIST_PANEL_CHECKBOX
// part of the layout_data_source_list object)
Evas_Object* data_source_checkbox;
// The list component (embedded into the PART_DATA_SOURCE_LIST_PANEL_LIST part of the
// layout_data_source_list object)
Evas_Object* data_source_list;
// The data source buttons panel layout (embedded into the PART_DATA_SOURCE_BUTTONS_PANEL
// part of the layout_data_source object)
Evas_Object* layout_data_source_buttons;
// The "Send" button component (embedded into the PART_DATA_SOURCE_BUTTONS_PANEL_SEND
// part of the layout_data_source_buttons object)
Evas_Object* data_source_button_send;
// The "Add" button component (embedded into the PART_DATA_SOURCE_BUTTONS_PANEL_ADD
// part of the layout_data_source_buttons object)
Evas_Object* data_source_button_add;
// The data sink view layout (embedded into the PART_MAIN_CONTENT part of the
// layout_main_panel object)
Evas_Object* layout_data_sink;
// The message entry component (embedded into the PART_DATA_SINK_ENTRY part of the
// layout_data_sink object)
Evas_Object* sink_entry;
} viewdata_s;

The modeldata_s structure contains a list of bundledata_s items,
where each of the bundledata_s structures contains data to be included in the bundle object. Additionally, the identifier of the message port for data receiving is declared.

The Bundle sample application is implemented using the MVC design pattern. Its initialization is done within the app_create() callback function where the controller_initialization() function is responsible for the application initialization. On the application termination, the app_terminate() callback function is called, and all the allocated resources are freed. For reference and more details,
see Controller.

View

The entire application layout is implemented using EDJE scripts. All top level swallows are designed for EFL Elementary component embedding. The following EDJE swallow - EFL Elementary component relations and assigned functionalities are used:

PART_MAIN_TOOLBAR-elm_toolbar: Switches the view between the data source and the data sink.

collections
{
group
{
name: GROUP_MAIN;
parts
{
// The background part occupies the entire window
part
{
name: PART_MAIN_BACKGROUND;
type: RECT;
}
// The part is positioned in relation to PART_MAIN_BACKGROUND
// The spacer occupies the entire area of PART_MAIN_BACKGROUND
// with a small margin all around
part
{
name: PART_MAIN_PANEL;
type: SPACER;
}
// The part is positioned in relation to PART_MAIN_PANEL
// The swallow occupies 6% of PART_MAIN_PANEL height
// It is designed to hold the elm_toolbar component
part
{
name: PART_MAIN_TOOLBAR;
type: SWALLOW;
}
// The part is positioned in relation to PART_MAIN_PANEL
// The swallow occupies 93% of PART_MAIN_PANEL height
// It is designed to hold the data source/data sink layout
part
{
name: PART_MAIN_CONTENT;
type: SWALLOW;
}
}
}
}

The data source and data sink layouts are switched by the toolbar item selection.

collections
{
group
{
name: GROUP_DATA_SOURCE;
parts
{
// The part is positioned in relation to PART_MAIN_CONTENT
// from the main.edc file
// The rect plays a role of the background for the edit panel
// and occupies the entire area
// of the PART_MAIN_CONTENT
part
{
name: PART_DATA_SOURCE_BACKGROUND;
type: RECT;
}
// The part is positioned in relation to
// PART_DATA_SOURCE_BACKGROUND
// The swallow part occupies 40% height and 100% width of the
// PART_DATA_SOURCE_BACKGROUND
// It is designed to hold the data source edit layout defined in
// data_source_edit_panel.edc
part
{
name: PART_DATA_SOURCE_EDIT_PANEL;
type: SWALLOW;
}
// The part is positioned in relation to
// PART_DATA_SOURCE_BACKGROUND
// The swallow part occupies 50% height and 100% width of the
// PART_DATA_SOURCE_BACKGROUND
// It is designed to hold the data source list layout defined in
// data_source_list_panel.edc
part
{
name: PART_DATA_SOURCE_LIST_PANEL;
type: SWALLOW;
}
// The part is positioned in relation to the
// PART_DATA_SOURCE_BACKGROUND
// The swallow part occupies 10% height and 100% width of the
// PART_DATA_SOURCE_BACKGROUND
// It is designed to hold the data source buttons layout defined in
// data_source_buttons_panel.edc
part
{
name: PART_DATA_SOURCE_BUTTONS_PANEL;
type: SWALLOW;
}
}
}
}

The PART_DATA_SOURCE_EDIT_PANEL swallow is used as a container for data edit (input) layout defined in the data_source_edit_panel.edc file (for more information, see Data source panel layout).

collections
{
group
{
name: GROUP_DATA_SOURCE_EDIT_PANEL;
parts
{
// The part is positioned in relation to
// PART_DATA_SOURCE_EDIT_PANEL from the data_source.edc file
// The rect plays a role of the background for the edit panel
// and occupies the entire area
// of the PART_DATA_SOURCE_EDIT_PANEL
part
{
name: PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND;
type: RECT;
}
// ----------=============== KEY NAME INPUT PANEL ===============----------
// The part is positioned in relation to
// PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND
// The swallow part occupies 33% height and 100% width of the
// PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND. It is designed to
// organize the key name editing area
part
{
name: PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL;
type: SPACER;
}
// The part is positioned in relation to
// PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL
// The text part occupies 100% height and 33% width of the
// PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL
// This part is responsible for static text label display
// only ("Key name")
part
{
name: "data_source_edit_panel_key_panel_label";
type: TEXT;
}
// The part is positioned in relation to
// PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL
// The rect plays a role of a background for the elm_entry
// component. Its size is set to
// 70% width and 70% height of the
// PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL.
// This part is vertically aligned
part
{
name: PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY_BACKGROUND;
type: RECT;
}
// The part is positioned in relation to
// PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY_BACKGROUND
// The swallow part occupies the entire area of the
// PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY_BACKGROUND
// It is designed to hold elm_entry component for key name input
part
{
name: PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY;
type: SWALLOW;
}
// ----------=============== VALUE INPUT PANEL ===============----------
// The layout of the PART_DATA_SOURCE_EDIT_PANEL_VALUE_PANEL
// part is exactly the same as the layout of the
// PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL part
// The only difference is that its vertical location is set
// to the 33% of PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND height
// For this reason, the source code is not listed here
// ----------=============== VALUE TYPE INPUT PANEL ===============----------
// The layout of the PART_DATA_SOURCE_EDIT_PANEL_TYPE_PANEL part
// is exactly the same as the layout of the
// PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL part
// There are only 2 differences:
// 1. Its height is set to 34% of the
// PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND height
// 2. Its vertical location is set to the 66% of the
// PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND height
// For this reason, the source code is not listed here
}
}
}

The PART_DATA_SOURCE_LIST_PANEL swallow is used as a container for the data source list layout defined in the data_source_list_panel.edc file (for more information, see Data source panel layout).

collections
{
group
{
name: GROUP_DATA_SOURCE_LIST_PANEL;
parts
{
// The part is positioned in relation to
// PART_DATA_SOURCE_LIST_PANEL from the data_source.edc file
// The rect plays a role of the background for the list panel
// and occupies the entire area of the
// PART_DATA_SOURCE_LIST_PANEL
part
{
name: PART_DATA_SOURCE_LIST_PANEL_BACKGROUND;
type: RECT;
}
// The part is positioned in relation to
// PART_DATA_SOURCE_LIST_PANEL_BACKGROUND
// The spacer part occupies 15% height and 100% width of the
// PART_DATA_SOURCE_LIST_PANEL_BACKGROUND
// It is designed to organize bundle header inclusion checkbox area
part
{
name: PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL;
type: SPACER;
}
// The part is positioned in relation to
// PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL
// The rect plays a role of a background for the elm_check component
// Its size is set to 9,7% width and 80% height of the
// PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL
// This part is vertically aligned. Its horizontal position is
// set to 60% width of the
// PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL
part
{
name: PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_BACKGROUND;
type: RECT;
}
// The part is positioned in relation to the
// PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL
// The text part occupies 80% height and 60% width of the
// PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL
// This part is vertically aligned and is responsible for static
// text label display only ("Include bundle header")
part
{
name: PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_LABEL;
type: TEXT;
}
// The part is positioned in relation to
// PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL.
// The swallow part occupies 80% height and 40% width of the
// PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL
// It is aligned next to the right border of the
// PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_LABEL and designed
// to hold the elm_check component for bundle header inclusion
part
{
name: PART_DATA_SOURCE_LIST_PANEL_CHECKBOX;
type: SWALLOW;
}
// The part is positioned in relation to
// PART_DATA_SOURCE_LIST_PANEL_BACKGROUND
// The swallow part occupies 100% width and 85% height of the
// PART_DATA_SOURCE_LIST_PANEL_BACKGROUND. It is aligned to the
// bottom border of the related part. It is designed to hold
// the elm_genlist component for input data display
part
{
name: PART_DATA_SOURCE_LIST_PANEL_LIST;
type: SWALLOW;
}
}
}
}

The PART_DATA_SOURCE_BUTTONS_PANEL swallow is used as a container for the data source buttons layout defined in the data_source_buttons_panel.edc file (for more information, see Data source panel layout).

collections
{
group
{
name: GROUP_DATA_SOURCE_BUTTONS_PANEL;
parts
{
// The part is positioned in relation to
// PART_DATA_SOURCE_BUTTONS_PANEL from data_source.edc file
// The rect plays a role of the background for the buttons
// panel and occupies the entire area of the
// PART_DATA_SOURCE_BUTTONS_PANEL
part
{
name: PART_DATA_SOURCE_BUTTONS_PANEL_BACKGROUND;
type: RECT;
}
// The part is positioned in relation to
// PART_DATA_SOURCE_BUTTONS_PANEL_BACKGROUND
// The swallow part occupies 80% height and 46% width of the
// PART_DATA_SOURCE_BUTTONS_PANEL_BACKGROUND
// Its left border is set to 2% width of related container
// Vertically, the swallow is centered
// This part is designed to hold the elm_button component for input data
// addition to the data list
part
{
name: PART_DATA_SOURCE_BUTTONS_PANEL_ADD;
type: SWALLOW;
}
// The part relations and sizing are the same as described
// above, for PART_DATA_SOURCE_BUTTONS_PANEL_ADD part
// The only difference is the left border positioning,
// which is set to 52% width of the
// PART_DATA_SOURCE_BUTTONS_PANEL_BACKGROUND part
// This part is designed to hold the elm_button component for bundle
// sending
part
{
name: PART_DATA_SOURCE_BUTTONS_PANEL_SEND;
type: SWALLOW;
}
}
}
}

The PART_MAIN_CONTENT swallow is used as a container for the data sink layout defined in the data_sink.edc file (for more information, see Main panel layout).

collections
{
group
{
name: GROUP_DATA_SINK;
parts
{
// The part is positioned in relation to PART_MAIN_CONTENT
// from main.edc file
// The rect plays a role of the background for the entry panel
// and occupies the entire area of the PART_MAIN_CONTENT
part
{
name: PART_DATA_SINK_BACKGROUND;
type: RECT;
}
// The part is positioned in relation to
// PART_DATA_SINK_BACKGROUND
// The swallow part occupies the entire area of
// PART_DATA_SINK_BACKGROUND
// This part is designed to hold the elm_entry component for
// received data display
part
{
name: PART_DATA_SINK_ENTRY;
type: SWALLOW;
}
}
}
}

Based on the layout defined with EDJE scripts, the application interface is created with the view_base_gui_create() function. The function takes 1 parameter, a pointer to the structure containing the view data. The view_base_gui_create() function is invoked in the controller_initialization() function called from the app_create() callback function. For the call stack details, see Application Initialization. The following code snippet presents the general steps in the user interface creation.

The entire application view creation is triggered by the view_base_gui_create() function described above. The result of the succeeding subfunction invocations is depicted in the following table.

Table: Base view creation code snippets and figures

Description

Code snippet

Figure

view_main_panel_create():

The main window and descendant conformant (vd->win and vd->conform respectively) are created and used as a placeholder for the main layout (vd->layout_main_panel).

The main layout is created with the view_generic_layout_create_set() function by loading the main group from the EDJE layout (main.edj file), then it is embedded into the vd->layout_main_panel container. Finally, the view_layout_back_cb() callback function is attached to the vd->layout_main_panel for the hardware Back button handling.

When the EDJE layout is successfully loaded, the elm_toolbar component can be created as a descendant of the main layout vd->layout_main_panel.

At the end, 2 items are appended to the newly created elm_toolbar component with the view_toolbar_item_selected_cb() callback function attached:

The view_toolbar_item_selected_cb() callback function is responsible for switching between the layout objects embedded to the PART_MAIN_CONTENT swallow of the vd->layout_main_panel. Those layouts are defined in the data_source.edc and data_sink.edc files.

The vd->layout_data_source_edit layout is created based on data_source_edit_panel.edc. The resulting layout is embedded into the PART_DATA_SOURCE_PANEL.

The elm_entry and elm_spinner components are created next and inserted into the vd->layout_data_source_edit layout. The newly created components are used for the bundle key name input (value and type, respectively). The elm_spinner component is then filled with the values reflecting all the available types of the key's value.

The vd->layout_data_source_list layout is created based on data_source_list_panel.edc. The resulting layout is embedded into the PART_DATA_SOURCE_LIST_PANEL.

The elm_check and the elm_genlist components are created next and inserted into the vd->layout_data_source_list layout. After the elm_check component is created, the view_checkbox_changed_cb() callback function is assigned to it in order to handle the component's state change event. For the implementation details of the view_checkbox_changed_cb() callback function, see User Interaction.

The vd->layout_data_source_buttons layout is created based on data_source_buttons_panel.edc. The resulting layout is embedded into the PART_DATA_SOURCE_BUTTONS_PANEL.

The 2 elm_button components are created next and inserted into the vd->layout_data_source_buttons layout. To each of the buttons created (vd->data_source_button_add, vd->data_source_button_send), the relevant callback function is attached for handling the click event:

view_button_add_clicked_cb(): handles input data adding to the list.

view_button_send_clicked_cb(): handles bundle creation and sending through the message port.

Within the view_button_add_clicked_cb() callback function, the input data provided by the user is gathered from the UI and packed into the bundledata_s structure (view_input_data_to_bundledata()) which is then added to the data list using the model_list_item_add() function.

Within the view_input_data_to_bundledata() function, the view_input_data_value_pointer_get() function's implementation is also omitted. It converts the str_value string to the relevant data type, based on the value_type set by the user, and assigns it to the provided ptr_value of void* type. The size of the data, referenced by the ptr_value, is returned in the val_size parameter. When all the data (key, value reference, and value type) are successfully acquired, the model_bundledata_create() function is called to create the bundledata_s structure (for implementation details, see Model). Otherwise, the view_input_data_to_bundledata() function fails and frees all previously allocated memory.

After the view_input_data_to_bundledata() function successfully returns and the bundledata_s structure is created, the model_list_item_add() function is invoked (refer to the view_button_add_clicked_cb() callback function) to store the structure for future use in a list of bundledata_s items. For the implementation details of the model_list_item_add() function, see Model.

The obtained input data is appended to the elm_genlist using the view_genlist_item_append() function.

To access the UI components directly, 3 simple functions are used: view_key_string_get(), view_value_string_get(), view_type_index_get(). Due to the implementation simplicity of the mentioned functions, they are not listed here.

The view_generic_genlist_item_class_create() function creates the genlist item class representing the visual style of all the items. The callback functions, passed as parameters (view_genlist_item_label_get_cb() and view_genlist_item_del_cb()), are used to control the display and release of the bundledata attached to the itc using the elm_genlist_item_append() function.

Within the view_genlist_item_append() function, the itc class together with the previously created bundledata_s structure are passed as parameters to the elm_genlist_item_append() function. As a result, a new item representing the user input data is appended to the elm_genlist component. The elm_genlist is scrolled so the newly appended item becomes visible (elm_genlist_item_bring_in()).

Including the Bundle Header

The user can add 1 additional key-value pair to the bundle, representing the data header (refer to the Bundle object structure depicted in the Bundle application workflow figure). By checking the Include bundle header checkbox, the elm_genlist component is updated with an additional item. The "real" header is added to the bundle object in the bundle creation phase (see Bundling and Sending the Data List). The Include bundle header checkbox state change results in the view_checkbox_changed_cb() callback function invocation.

Bundling and Sending the Data List

When the user clicks Send, the view_button_send_clicked_cb() callback is triggered and creates the bundle object (with respect to the state of the Include bundle header checkbox). Afterwards, the bundle is sent using a message port.

When the application is terminated, the controller_terminate() function is called. It is responsible for freeing all the allocated memory, deleting the user interface, and releasing the related resources. For more information about the used functions, see Data Sink Controller, View, and Model.

Data Source Controller

The data source controller module is responsible for data bundling and sending using a message port. The function triggering the entire process (controller_data_source_message_send()) is referenced in Bundling and Sending the Data List.

All user input data stored in a list is obtained simply by referencing the Eina_List object, declared in the Model module, in the model_data_list_get() function.

The empty bundle object is created with the model_bundle_create() function (for reference, see Bundle Model).

The data addition to the bundle object starts with the controller_data_source_bundle_header_create() function call.

The function adds the HEADER key with 0 or 1 value to the bundle_msg bundle object. The 0 or 1 value is assigned depending on the include_header variable value. If the include_header == 1, the additional HEADER_DATA key is added to the bundle_msg bundle object. The value type of the HEADER_DATA key is an array of strings, where all the cells of the array are filled with key names defined by the user during the data input procedure (for reference, see Inputting Data and Adding to the List).

To finalize the data addition process, all the user-defined key-value pairs are appended to the bundle object with the controller_data_source_bundle_data_add() function.

Once the bundle object is successfully created and populated with the data, it is sent through the message port using the model_message_port_message_send() function (for reference, see Message Port Model).

After the bundle_msg is sent, it is not needed anymore, so it can be deleted with the model_bundle_destroy() function (for reference, see Bundle Model).

Data Sink Controller

The data sink controller module is responsible for the initialization and finalization of the communication channel using a message port and receiving messages. The data sink initialization function (controller_data_sink_create()) is invoked from the controller_initialization() function contained in the general Controller module. Similarly, the finalization function (controller_data_sink_destroy()) is called from the controller_terminate() function contained in the same general Controller module.

In the message port initialization procedure, a new communication channel is created with the controller_data_sink_message_received_cb() callback function attached. When a new message arrives, the callback function is invoked and the received data passed in the callback.

bool
controller_data_sink_destroy(void)
{
// If the message port was never created, there is nothing to do
if (!model_message_port_exists_check())
{
return true;
}
// Close the communication channel and the message port
return model_message_port_destroy();
}

When a new message arrives through the created message port, the controller_data_sink_message_received_cb() callback function is invoked. The general approach of data extraction from the received bundle object is based on the knowledge about its structure (see the bundle object structure depicted in the Bundle application workflow figure). The workflow can be described with the following steps:

Get the number of bundled items.

Get the value of BUNDLE_HEADER_KEY:

If the value of BUNDLE_HEADER_KEY equals 1, the data header is included and must be extracted using the model_bundle_string_array_get() function. As a result, the string array is returned.

If the value of BUNDLE_HEADER_KEY equals 0, the data header is not included.

If the bundle data header exists, it is printed to the data sink view.

Bundle data enumeration is performed using the model_bundle_foreach() function with the controller_data_sink_bundle_foreach_cb() callback function attached.

Once the data header is decoded and extracted, the enumeration of data items starts (model_bundle_foreach()). For each bundled item, the controller_data_sink_bundle_foreach_cb() callback function is invoked.

Model

The general Model module deals directly with the application data. It is responsible for:

Model initialization and finalization

User data list handling

In the initialization step, the model_data_create() function is invoked from the controller_initialization() function. The model_data_destroy() function is called in the application termination phase by the controller_terminate() function. For the call stack reference, see Controller.

The user input data are added to the list with the model_bundledata_create() function referenced from the view_input_data_to_bundledata() function, which is called by the view_button_add_clicked_cb() callback function on the Add button press. For reference, see Inputting Data and Adding to the List.

Once the user input data structure (bundledata_s described in Type Definitions) is created, it can be added to the list with the model_list_item_add() function and accessed with the model_data_list_get() function. The first function is invoked from the view_button_add_clicked_cb() callback function (see Inputting Data and Adding to the List) and the second one is called during the data bundling and sending procedure (controller_data_source_message_send() referenced in Data Source Controller). The implementation of both functions is very simple and limited to proper Eina_List function invocations. For this reason, they are not listed here.

Bundle Model

The Bundle model module provides a set of wrapper functions for the Bundle API used by the Controller module for the bundle management:

bool
model_bundle_keyval_type_get(const bundle_keyval_t *kv, int *type)
{
// The type of the bundled item's value is acquired
// This function is used within the callback function invoked by the bundle_foreach() function
// If the returned value is non-negative, it points to the value type. Otherwise, the error code is returned
*type = bundle_keyval_get_type((bundle_keyval_t*)kv);
int ret = get_last_result();
// Error handling
return true;
}