Within normal ABAP reporting, if we are doing some long queries or posting a lot of transactions we would use the FM SAPGUI_PROGRESS_INDICATOR to stop the report from timing out. The same scenario can happen in WebDynpro as well. By default a WebDynpro application times out in 5 minutes. So posting a lot of transaction becomes a problem here too. WebDynpro does not provide a similar function to SAPGUI_PROGRESS_INDICATOR yet (coming in 7.1?).
So we would have to implement our own progress indicator by creating a WebDynpro component using UI elements TimedTrigger and ProgressIndicator. UI element TimedTrigger is an invisible element which when placed on a view, triggers an event every given number of seconds. This is an expensive UI element to have as it creates additional burden on the server, but we have no choice so we will use this. UI element ProgressIndicator is used to show a progress bar. So the idea is to split big job into chunks that can be done in small amount of time (less than the time out period). Every time TimedTrigger fires an event we process the next available chunk of work and set the progress bar and so on.
The calling WD component will use this component for displaying the progress bar and getting a timed wake up call. The calling WD will already have the dataset ready. It would decide how many chunks the dataset will be needed divide into. So once the user triggers the action this progress indicator (PI) WD component is called in a dialog window. The calling WD subscribes to the PI WD event of timed trigger so that it wakes up to send next chunk of data. Using the assistance class of PI WD the calling WD will set the percentage of data completion as well so that the progress bar will keep on increasing.
Let’s see what we need to create in this PI WD component:
UI elements in the view
Layout
Components
Context
Events
Methods of the Component Controller
ACTION_KEEP_ALIVE | call from timed trigger |
GET_MODEL | Return the model class |
INIT_PROG_VIEW | Initialise progress view |
RAISE_WINDOW_CLOSE | Raise event for window closed |
SET_PERCENTAGE | Set percentage complete |
SET_PROGRESS_MSG | Set progress message |
ACTION_KEEP_ALIVE
set_percentage( ).
wd_this->fire_keep_alive_evt( ).
GET_MODEL
r_o_model = wd_assist.
INIT_PROG_VIEW
wd_assist->set_percent_comp( 0 ).
wd_this->set_percentage( ).
wd_this->set_progress_msg( ).
RAISE_WINDOW_CLOSE
wd_this->fire_window_close_evt(
).
SET_PERCENTAGE
DATA lo_nd_progress
TYPE REF TO if_wd_context_node
. DATA lo_el_progress
TYPE REF TO if_wd_context_element
. DATA ls_progress
TYPE wd_this
->element_progress. DATA lv_percent
LIKE ls_progress
-percent
. * navigate from <CONTEXT> to <PROGRESS> via lead selection
lo_nd_progress = wd_context->get_child_node( name = wd_this->wdctx_progress ).
* get element via lead selection
lo_el_progress = lo_nd_progress->get_element( ).
lv_percent = wd_assist->get_percent_comp( ).
* get single attribute
lo_el_progress->set_attribute(
EXPORTING
name = `PERCENT`
value = lv_percent ).
SET_PROGRESS_MSG
DATA lo_nd_progress
TYPE REF TO if_wd_context_node
. DATA lo_el_progress
TYPE REF TO if_wd_context_element
. DATA ls_progress
TYPE wd_this
->element_progress. * navigate from <CONTEXT> to <PROGRESS> via lead selection
lo_nd_progress = wd_context->get_child_node( name = wd_this->wdctx_progress ).
* get element via lead selection
lo_el_progress = lo_nd_progress->get_element( ).
lv_message = wd_assist->get_progress_msg( ).
* get single attribute
lo_el_progress->set_attribute(
EXPORTING
name = `MESSAGE`
value = lv_message ).
The assistance class has these methods:
GET_PROGRESS_MSG | Get the progress message |
SET_PROGRESS_MSG | Set the message in the progress bar |
SET_PERCENT_COMP | Returns the percentage done |
GET_PERCENT_COMP | Returns the percentage done |
These are just getter and setter methods for the filling the Context variables. The calling WD component can set the percentage and message to be displayed. The PI WD will read these values and set in the context.
Usage
Let’s look at the usage of the progress indicator in a example WD component. Create a new WD where we will use the PI WD component. Add the PI WD component in the properties.
In the component controller properties add it as used component comptroller.
Subscribe to the events of the PI WD component.
This catches events for timed trigger and window close in case user cancels before 100% completion of the process.
CATCH_TIMED_TRIGGER
METHOD catch_timed_trigger .
DATA l_percentage TYPE i.
l_percentage = wd_this->o_zcl_rc_library->get_percent_comp( ).
IF l_percentage >= 100.
wd_this->o_progress_window->close( ).
ENDIF.
l_percentage = l_percentage + 10.
wd_this->o_zcl_rc_library->set_percent_comp( l_percentage ).
ENDMETHOD.
We are here just incrementing the percentage by 10% each time the trigger is activated. But in real situation one would increment to the next dataset that is planned to be processed. The percentage will be according to that.
CATCH_WINDOW_CLOSE
METHOD catch_window_close .
* Check action
is over because it
is finished or
* killed in between
CHECK wd_this->flag_action_start = abap_true. " Action is killed
" ERROR
* get message manager
DATA lo_api_controller TYPE REF TO if_wd_controller.
DATA lo_message_manager TYPE REF TO if_wd_message_manager.
lo_api_controller ?= wd_this->wd_get_api( ).
lo_message_manager = lo_api_controller->get_message_manager( ).
* report message
lo_message_manager->report_error_message(
message_text = 'Window cancelled before process completion'
).
* Clear variables
CASE wd_this->action.
WHEN 1. " Validate
WHEN 2. " Action
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
If the progress window is closed before all data has been processed you can alert the user that with that error.
Let’s look at the component controllers methods.
WDDOINIT
METHOD wddoinit .
DATA lo_cmp_usage TYPE REF TO if_wd_component_usage.
lo_cmp_usage = wd_this->wd_cpuse_zwdrc_progress_window( ).
IF lo_cmp_usage
->has_active_component
( ) IS INITIAL
. lo_cmp_usage->create_component( ).
ENDIF.
DATA lo_interfacecontroller TYPE REF TO ziwci_wdrc_progress_window .
lo_interfacecontroller = wd_this->wd_cpifc_zwdrc_progress_window( ).
wd_this->o_zcl_rc_library = lo_interfacecontroller->get_model( ).
ENDMETHOD.
This will initialise the PI WD component and get the assistance class handler.
We have a simple example which has a button that will launch the progress window.
The action attached to the button is:
ONACTIONCALL_PROGRESS
METHOD onactioncall_progress .
wd_comp_controller->open_progress_window( ).
ENDMETHOD.
Here the real application would start the working of whatever transaction was planned. The progress window is further opened as:
OPEN_PROGRESS_WINDOW
METHOD open_progress_window .
DATA lo_componentinterface TYPE REF TO if_wd_component_usage.
lo_componentinterface = wd_this->wd_cpuse_zwdrc_progress_window( ).
DATA lo_interface TYPE REF TO ziwci_wdrc_progress_window.
lo_interface = wd_this->wd_cpifc_zwdrc_progress_window( ).
wd_this->o_zcl_rc_library->set_progress_msg( 'We are doing it ').
wd_this->o_zcl_rc_library->set_percent_comp( 0 ).
DATA lo_cont TYPE REF TO if_wd_controller.
* if_wd_controller = lo_interface->wd_get_api( ).
DATA lo_api_componentcontroller TYPE REF TO if_wd_component.
lo_api_componentcontroller = wd_this->wd_get_api( ).
DATA l_window_manager TYPE REF TO if_wd_window_manager.
l_window_manager = lo_api_componentcontroller->get_window_manager( ).
wd_this->o_progress_window = l_window_manager->create_window_for_cmp_usage(
interface_view_name = 'W_MAIN'
component_usage_name = 'ZWDRC_PROGRESS_WINDOW'
title = 'We are doing it'
* close_in_any_case = ABAP_TRUE
* message_display_mode = message_display_mode
).
* wd_this->o_progress_window->set_window_title( title = 'Test' ).
wd_this->o_progress_window->open( ).
ENDMETHOD.
Here the window W_MAIN of PI WD component is being called. The title is set and so is the message that will come in the message bar.
Here is the example of the output:
10% done
20% done