Friday, September 10, 2010

WebDynpro: Progress indicator (similar to SAPGUI_PROGRESS_INDICATOR)

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:

clip_image002 UI elements in the view

clip_image004 Layout

image Components

image Context

image 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
  1. METHOD action_keep_alive .
  2. set_percentage( ).
  3. wd_this->fire_keep_alive_evt( ).


GET_MODEL
  1. METHOD get_model .
  2. r_o_model = wd_assist.


INIT_PROG_VIEW
  1. method INIT_PROG_VIEW .
  2. wd_assist->set_percent_comp( 0 ).
  3. wd_this->set_percentage( ).
  4. wd_this->set_progress_msg( ).


RAISE_WINDOW_CLOSE
  1. METHOD raise_window_close .
  2. wd_this->fire_window_close_evt(
  3. ).


SET_PERCENTAGE
  1. METHOD set_percentage .
  2. DATA lo_nd_progress TYPE REF TO if_wd_context_node.
  3. DATA lo_el_progress TYPE REF TO if_wd_context_element.
  4. DATA ls_progress TYPE wd_this->element_progress.
  5. DATA lv_percent LIKE ls_progress-percent.
  6. * navigate from <CONTEXT> to <PROGRESS> via lead selection
  7. lo_nd_progress = wd_context->get_child_node( name = wd_this->wdctx_progress ).
  8. * get element via lead selection
  9. lo_el_progress = lo_nd_progress->get_element( ).
  10. lv_percent = wd_assist->get_percent_comp( ).
  11. * get single attribute
  12. lo_el_progress->set_attribute(
  13. EXPORTING
  14. name = `PERCENT`
  15. value = lv_percent ).


SET_PROGRESS_MSG
  1. METHOD set_progress_msg .
  2. DATA lo_nd_progress TYPE REF TO if_wd_context_node.
  3. DATA lo_el_progress TYPE REF TO if_wd_context_element.
  4. DATA ls_progress TYPE wd_this->element_progress.
  5. DATA lv_message LIKE ls_progress-message.
  6. * navigate from <CONTEXT> to <PROGRESS> via lead selection
  7. lo_nd_progress = wd_context->get_child_node( name = wd_this->wdctx_progress ).
  8. * get element via lead selection
  9. lo_el_progress = lo_nd_progress->get_element( ).
  10. lv_message = wd_assist->get_progress_msg( ).
  11. * get single attribute
  12. lo_el_progress->set_attribute(
  13. EXPORTING
  14. name = `MESSAGE`
  15. 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.

image

In the component controller properties add it as used component comptroller.

image

Subscribe to the events of the PI WD component.

image

This catches events for timed trigger and window close in case user cancels before 100% completion of the process.

CATCH_TIMED_TRIGGER
  1. METHOD catch_timed_trigger .
  2. DATA l_percentage TYPE i.
  3. l_percentage = wd_this->o_zcl_rc_library->get_percent_comp( ).
  4. IF l_percentage >= 100.
  5. wd_this->o_progress_window->close( ).
  6. ENDIF.
  7. l_percentage = l_percentage + 10.
  8. wd_this->o_zcl_rc_library->set_percent_comp( l_percentage ).
  9. 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
  1. METHOD catch_window_close .
  2. * Check action is over because it is finished or
  3. * killed in between
  4. CHECK wd_this->flag_action_start = abap_true. " Action is killed
  5. " ERROR
  6. * get message manager
  7. DATA lo_api_controller TYPE REF TO if_wd_controller.
  8. DATA lo_message_manager TYPE REF TO if_wd_message_manager.
  9. lo_api_controller ?= wd_this->wd_get_api( ).
  10. lo_message_manager = lo_api_controller->get_message_manager( ).
  11. * report message
  12. lo_message_manager->report_error_message(
  13. message_text = 'Window cancelled before process completion'
  14. ).
  15. * Clear variables
  16. CASE wd_this->action.
  17. WHEN 1. " Validate
  18. WHEN 2. " Action
  19. WHEN OTHERS.
  20. ENDCASE.
  21. 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
  1. METHOD wddoinit .
  2. DATA lo_cmp_usage TYPE REF TO if_wd_component_usage.
  3. lo_cmp_usage = wd_this->wd_cpuse_zwdrc_progress_window( ).
  4. IF lo_cmp_usage->has_active_component( ) IS INITIAL.
  5. lo_cmp_usage->create_component( ).
  6. ENDIF.
  7. DATA lo_interfacecontroller TYPE REF TO ziwci_wdrc_progress_window .
  8. lo_interfacecontroller = wd_this->wd_cpifc_zwdrc_progress_window( ).
  9. wd_this->o_zcl_rc_library = lo_interfacecontroller->get_model( ).
  10. 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.

image

The action attached to the button is:

ONACTIONCALL_PROGRESS
  1. METHOD onactioncall_progress .
  2. wd_comp_controller->open_progress_window( ).
  3. ENDMETHOD.
Here the real application would start the working of whatever transaction was planned. The progress window is further opened as:

OPEN_PROGRESS_WINDOW
  1. METHOD open_progress_window .
  2. DATA lo_componentinterface TYPE REF TO if_wd_component_usage.
  3. lo_componentinterface = wd_this->wd_cpuse_zwdrc_progress_window( ).
  4. DATA lo_interface TYPE REF TO ziwci_wdrc_progress_window.
  5. lo_interface = wd_this->wd_cpifc_zwdrc_progress_window( ).
  6. wd_this->o_zcl_rc_library->set_progress_msg( 'We are doing it ').
  7. wd_this->o_zcl_rc_library->set_percent_comp( 0 ).
  8. DATA lo_cont TYPE REF TO if_wd_controller.
  9. * if_wd_controller = lo_interface->wd_get_api( ).
  10. DATA lo_api_componentcontroller TYPE REF TO if_wd_component.
  11. lo_api_componentcontroller = wd_this->wd_get_api( ).
  12. DATA l_window_manager TYPE REF TO if_wd_window_manager.
  13. l_window_manager = lo_api_componentcontroller->get_window_manager( ).
  14. wd_this->o_progress_window = l_window_manager->create_window_for_cmp_usage(
  15. interface_view_name = 'W_MAIN'
  16. component_usage_name = 'ZWDRC_PROGRESS_WINDOW'
  17. title = 'We are doing it'
  18. * close_in_any_case = ABAP_TRUE
  19. * message_display_mode = message_display_mode
  20. ).
  21. * wd_this->o_progress_window->set_window_title( title = 'Test' ).
  22. wd_this->o_progress_window->open( ).
  23. 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:

image 10% done

image 20% done