Utility Class for ALV Legend on SALV Grid

By | August 11, 2014 | Utilities | 8,501 | 5

Utility class to generate the Legend ALV using SALV Popup and attach it onto ALV Grid generated by SALV Model

Preface

When I design the ALV to display the report, many times I use the Icons on the output. Icons enhances the visual display of the grid and would provide nice look to the reports. Read SALV Table 18 – ICONs and Tooltips to understand more about adding the icons on SALV.

On other day, I thought of adding the legend button on the ALV so user can better understand the purpose of the icon, to make it more user friendly. I added the button on the grid, I handled the event and I displayed the ALV in SALV Popup. I designed another ALV report and had to generate the legend again. So, I thought of creating an utility class which can be bolt on to the ALV with minimal coding by inheritance.

Utility class ZCL_ICON_LEGEND

The class is based on the idea:

  • Get the parent ALV data table. Here the Parent ALV is the ALV on which you want to add the legend ALV
  • Fill up the Icon and its descriptions
  • Add button on the Parent ALV to display the legend ALV
  • Event handler for the button on Parent ALV to display the legend ALV

Class Attributes:

These are the attributes in the utility class ZCL_ICON_LEGEND

  • T_LEGEND – Table with Icon and its description
  • V_BTN_OKCODE – OK code for Button on Parent ALV
  • V_BTN_ICON – Button’s ICON
  • V_BTN_TOOLTIP – Button’s tooltip
  • V_BTN_TEXT – Button’s Text
  • V_FIELD – Protected with Field name for the Icon column from parent ALV
  • O_DATA – Protected data reference to the parent ALV data

Class methods:

These are the methods in the utility class ZCL_ICON_LEGEND

  • GENERATE_LEGEND_OUTPUT – This method adds the button on parent ALV using the attributes and have event handler
  • SET_DESCRIPTION – protected method to allow to change the description on the legend output table

Features

Few highlights of the features:

  • If parent ALV is not SALV Grid, the object would raise an exception {Read Class-based Exceptions I – Basics}
  • You can add more than buttons with more than one instance of the objects
  • Default button property is set, no need to change anything if only one legend
  • You can change the button properties for each button
  • Default description for blank icon is set

UML

High level UML on how ZCL_ICON_LEGEND can be used:

Class Code Lines

Here we go

 
*----------------------------------------------------------------------*
* Author: Naimesh Patel
* Desc	: Utility to generate Legend ALV on SALV Grid ALV
* Link  : http://zevolving.com/?p=2786
*----------------------------------------------------------------------*
CLASS zcl_icon_legend DEFINITION.
  PUBLIC SECTION.
    TYPES:
      BEGIN OF ty_legend,
        icon_val    TYPE char30,
        desc        TYPE char50,
      END   OF ty_legend.
    TYPES: tt_legend TYPE STANDARD TABLE OF ty_legend.
 
    METHODS:
      constructor
        IMPORTING
          it_data TYPE STANDARD TABLE
          iv_field TYPE char30
          io_parent_salv TYPE REF TO cl_salv_table
        EXCEPTIONS type cx_salv_method_not_supported,
      generate_legend_output.
    DATA: t_legend         TYPE tt_legend.
    DATA: v_btn_okcode     TYPE salv_de_function.
    DATA: v_btn_icon       TYPE string.
    DATA: v_btn_tooltip    TYPE string.
    DATA: v_btn_text       TYPE string.
 
  PROTECTED SECTION.
    METHODS:
      set_description.
    DATA: v_field         TYPE char30.
    DATA: o_data          TYPE REF TO data.
 
  PRIVATE SECTION.
    DATA: o_parent_salv    TYPE REF TO cl_salv_table.
    DATA: o_legend_salv    TYPE REF TO cl_salv_table.
    METHODS:
      on_user_command FOR EVENT added_function OF cl_salv_events_table
        IMPORTING
          e_salv_function.
 
ENDCLASS.                    "zcl_icon_legend DEFINITION
 
*
CLASS zcl_icon_legend IMPLEMENTATION.
  METHOD constructor.
 
* Only on Grid
    o_parent_salv = io_parent_salv.
    IF o_parent_salv->get_display_object( ) NE if_salv_c_table_objects=>grid.
      RAISE cx_salv_method_not_supported.
    ENDIF.
 
    me->v_field = iv_field.
    GET REFERENCE OF it_data INTO o_data.
** Fill up the Legend table
*    me->set_description( it_data ).
 
* Default values for the button
*   Change in the legend object, if there are more than one legend buttons
    me->v_btn_okcode  = 'LEGEND'.
    me->v_btn_icon    = icon_question.
    me->v_btn_tooltip = 'Legend'.
 
 
  ENDMETHOD.                    "constructor
  METHOD set_description.
 
    FIELD-SYMBOLS: <ft_data> TYPE ANY TABLE,
                   <fs_data> TYPE any,
                   <fs_fld>  TYPE any.
    DATA: ls_legend LIKE LINE OF t_legend.
 
    ASSIGN o_data->* TO <ft_data>.
 
    LOOP AT <ft_data> ASSIGNING <fs_data>.
      ASSIGN COMPONENT me->v_field
        OF STRUCTURE <fs_data> TO <fs_fld>.
      IF <fs_fld> IS NOT ASSIGNED.
        "raise"
        EXIT.
      ENDIF.
      ls_legend-icon_val = <fs_fld>.
      COLLECT ls_legend INTO t_legend.
      CLEAR   ls_legend.
    ENDLOOP.
 
*   For empty
    READ TABLE t_legend INTO ls_legend WITH KEY icon_val = space.
    IF sy-subrc EQ 0.
      ls_legend-desc = '<no desc>'.
      MODIFY t_legend FROM ls_legend INDEX sy-tabix.
    ENDIF.
 
  ENDMETHOD.                    "set_description
  METHOD generate_legend_output.
 
* Get the descriptions
    me->set_description( ).
 
* Add button for Legend on Parent
    DATA: lo_functions            TYPE REF TO cl_salv_functions_list.
    DATA: lo_events               TYPE REF TO cl_salv_events_table.
    lo_functions = o_parent_salv->get_functions( ).
    TRY.
        lo_functions->add_function(
            name     = me->v_btn_okcode
            icon     = me->v_btn_icon
            tooltip  = me->v_btn_tooltip
            text     = me->v_btn_text
            position = if_salv_c_function_position=>right_of_salv_functions
            ).
      CATCH cx_salv_existing .
      CATCH cx_salv_wrong_call .
    ENDTRY.
 
* Add event handler for parent
    lo_events = o_parent_salv->get_event( ).
    SET HANDLER me->on_user_command FOR lo_events.
 
  ENDMETHOD.                    "generate_legend_output
 
*
  METHOD on_user_command.
 
* Handle the Legend Button event.
    CHECK e_salv_function = me->v_btn_okcode.
 
    DATA: lr_functions TYPE REF TO cl_salv_functions_list.
    DATA: lo_columns              TYPE REF TO cl_salv_columns.
    DATA: lo_column               TYPE REF TO cl_salv_column_table.
    DATA: ls_color                TYPE lvc_s_colo.    " Colors strucutre
    INCLUDE <color>.
 
 
* Create new Legend ALV
    IF o_legend_salv IS NOT BOUND.
      TRY.
          cl_salv_table=>factory(
            IMPORTING
              r_salv_table = o_legend_salv
            CHANGING
              t_table      = t_legend ).
        CATCH cx_salv_msg.                              "#EC NO_HANDLER
      ENDTRY.
 
* default functions
      lr_functions = o_legend_salv->get_functions( ).
      lr_functions->set_default( 'X' ).
      lr_functions->set_group_sort( ' ' ).
 
* ICON column with color background
      lo_columns = o_legend_salv->get_columns( ).
      ls_color-col = col_total.
      TRY.
          lo_column ?= lo_columns->get_column( 'ICON_VAL' ).
          lo_column->set_icon( if_salv_c_bool_sap=>true ).
          lo_column->set_long_text( 'ICON' ).
          lo_column->set_alignment( if_salv_c_alignment=>centered ).
          lo_column->set_output_length( 10 ).
          lo_column->set_color( ls_color ).
        CATCH cx_salv_not_found.                        "#EC NO_HANDLER
      ENDTRY.
 
      TRY.
          lo_column ?= lo_columns->get_column( 'DESC' ).
          lo_column->set_long_text( 'Description' ).
        CATCH cx_salv_not_found.                        "#EC NO_HANDLER
      ENDTRY.
 
 
* .. as popup
      o_legend_salv->set_screen_popup(
        start_column = 80
        end_column   = 140
        start_line   = 3
        end_line     = 10 ).
 
    ENDIF.
 
* And Display
    o_legend_salv->display( ).
 
  ENDMETHOD.                    "on_user_command
ENDCLASS.                    "zcl_icon_legend IMPLEMENTATION
 

Utility Usage

Inherit the utility class in your local class. This would allow you to modify the description of the icons. Once the class is inherited, redefine the method SET_DESCRIPTION( ).

While generating the ALV, instantiate the legend object using the inherited local class.

Demo Code lines

*
CLASS lcl_icon_legend_status DEFINITION INHERITING FROM zcl_icon_legend.
  PROTECTED SECTION.
    METHODS:
      set_description REDEFINITION.
ENDCLASS.                    "lcl_icon_legend_status DEFINITION
 
INCLUDE <icon>.
*
CLASS lcl_report DEFINITION.
*
  PUBLIC SECTION.
    TYPES:
      BEGIN OF ty_t100.
            INCLUDE TYPE t100.
    TYPES:
        s_icon      TYPE char08,
        s_new_stat  TYPE char08,
      END OF ty_t100.
 
    DATA: t_t100 TYPE STANDARD TABLE OF ty_t100.
 
    DATA: o_salv TYPE REF TO cl_salv_table.
    DATA: o_container TYPE REF TO cl_gui_custom_container.
 
    METHODS:
      get_data,
      generate_output.
 
ENDCLASS.                    "lcl_report DEFINITION
 
 
START-OF-SELECTION.
  DATA: lo_report TYPE REF TO lcl_report.
  CREATE OBJECT lo_report.
  lo_report->get_data( ).
 
 
  CALL SCREEN 9000.
 
*----------------------------------------------------------------------*
*       CLASS lcl_report IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_report IMPLEMENTATION.
  METHOD get_data.
*   data selection
    SELECT * FROM t100
      INTO TABLE t_t100
      UP TO 10 ROWS
      WHERE sprsl = sy-langu.
 
    FIELD-SYMBOLS: <ls_t100> LIKE LINE OF t_t100.
    DO 3 TIMES.
      READ TABLE t_t100 ASSIGNING <ls_t100> INDEX sy-index.
      <ls_t100>-s_icon = icon_red_light.
    ENDDO.
    DO 2 TIMES.
      READ TABLE t_t100 ASSIGNING <ls_t100> INDEX ( sy-tabix + 3 ).
      <ls_t100>-s_icon = icon_yellow_light.
    ENDDO.
 
  ENDMETHOD.                    "get_data
*
*
  METHOD generate_output.
 
    CREATE OBJECT o_container
      EXPORTING
        container_name = 'CONTAINER'.
 
 
    DATA: lo_msg TYPE REF TO cx_salv_msg.
    TRY.
        cl_salv_table=>factory(
          EXPORTING
            r_container    = o_container
            container_name = 'CONTAINER'
          IMPORTING
            r_salv_table = o_salv
          CHANGING
            t_table      = t_t100 ).
      CATCH cx_salv_msg INTO lo_msg.
    ENDTRY.
 
    DATA: lo_functions TYPE REF TO cl_salv_functions_list.
    lo_functions = o_salv->get_functions( ).
    lo_functions->set_all( abap_true ).
 
* First Legend button
    TRY .
        DATA: o_legend TYPE REF TO lcl_icon_legend_status.
        CREATE OBJECT o_legend
          EXPORTING
            it_data        = t_t100
            iv_field       = 'S_ICON'
            io_parent_salv = o_salv.
        "SET HANDLER on_modify_desc FOR o_legend.
        o_legend->generate_legend_output( ).
      CATCH cx_salv_method_not_supported .
        MESSAGE 'Legend Toolbar not supported' TYPE 'S'.
    ENDTRY.
 
* second Legend button
* Notice the changes to the button properties
    TRY.
        DATA: o_legend_2 TYPE REF TO zcl_icon_legend.
        CREATE OBJECT o_legend_2
          EXPORTING
            it_data        = t_t100
            iv_field       = 'S_NEW_STAT'
            io_parent_salv = o_salv.
        o_legend_2->v_btn_okcode  = 'LEGEND_NEW'.
        o_legend_2->v_btn_tooltip = 'New Legend'.
        o_legend_2->v_btn_text    = 'New Legend'.
        o_legend_2->v_btn_icon    = icon_okay.
        "SET HANDLER on_modify_desc FOR o_legend_2.
        o_legend_2->generate_legend_output( ).
      CATCH cx_salv_method_not_supported .
        MESSAGE 'Legend Toolbar not supported' TYPE 'S'.
    ENDTRY.
 
* default descriptions
    DATA: lo_cols     TYPE REF TO  cl_salv_columns,
          lo_column   TYPE REF TO  cl_salv_column_list,
          lt_cols     TYPE         salv_t_column_ref,
          ls_cols     LIKE LINE OF lt_cols.
 
    DATA: lv_short    TYPE scrtext_s.
    DATA: lv_med      TYPE scrtext_m.
    DATA: lv_long     TYPE scrtext_l.
 
    lo_cols = o_salv->get_columns( ).
    lo_cols->set_optimize( 'X' ).
 
    lt_cols    = lo_cols->get( ).
 
    LOOP AT lt_cols INTO ls_cols.
      lo_column ?= ls_cols-r_column.    "Narrow casting
      IF lo_column->get_short_text( ) IS INITIAL.
        lv_short = ls_cols-columnname.
        lo_column->set_short_text( lv_short ).
      ENDIF.
      IF lo_column->get_medium_text( ) IS INITIAL.
        lv_med = ls_cols-columnname.
        lo_column->set_medium_text( lv_med ).
      ENDIF.
      IF lo_column->get_long_text( ) IS INITIAL.
        lv_long = ls_cols-columnname.
        lo_column->set_long_text( lv_long ).
      ENDIF.
 
    ENDLOOP.
 
* Displaying the ALV
    o_salv->display( ).
  ENDMETHOD.                    "generate_output
 
ENDCLASS.                    "lcl_report IMPLEMENTATION
 
*
CLASS lcl_icon_legend_status IMPLEMENTATION.
  METHOD set_description.
 
*   call default logic
    super->set_description( ).
 
*
    FIELD-SYMBOLS: <ls_legend> LIKE LINE OF me->t_legend.
 
    READ TABLE me->t_legend ASSIGNING <ls_legend>
      WITH KEY icon_val = icon_red_light.
    IF sy-subrc EQ 0.
      <ls_legend>-desc = 'Critical Error'.
    ENDIF.
 
    READ TABLE me->t_legend ASSIGNING <ls_legend>
      WITH KEY icon_val = icon_yellow_light.
    IF sy-subrc EQ 0.
      <ls_legend>-desc = 'Warning, with caution'.
    ENDIF.
 
 
  ENDMETHOD.                    "set_description
ENDCLASS.                    "lcl_icon_legend_status IMPLEMENTATION
 
*----------------------------------------------------------------------*
*  MODULE STATUS_9000 OUTPUT
*----------------------------------------------------------------------*
MODULE status_9000 OUTPUT.
 
  IF  lo_report->o_salv IS NOT BOUND.
    lo_report->generate_output( ).
  ELSE.
    lo_report->o_salv->refresh( ).
  ENDIF.
 
ENDMODULE.                    "STATUS_9000 OUTPUT
 

Demo Output

In Action:

One more button, in action

Like It? Share!!

Don't miss an Update

Get notified of the new post, right into your inbox

Naimesh Patel{274 articles}

I'm SAP ABAP Consultant for more than a decade. I like to experiment with ABAP especially OO. I have been SDN Top Contributor.
Follow :

Explore all of his 274 articles.

Load comments

5 Comments

  • Markus

    Hi,

    Nice idea!

    I would provide a static method for adding the legends buttons in a standard way… 🙂

  • steve oldner

    Very cool! Haven’t ever thought about doing that.

    I will see if I can use this next ALV I write!

    Can we do something like this in webdynpro?

  • Shai

    Hi,
    Nice approach.

    Two suggestions:
    1. I would prefer one context/column related legend button over separate buttons. i.e. displaying relevant legend according selected column.
    2. Wouldn’t it be more elegant to use icons with tooltips?
    In such case, you may build the legend automaically/dynamically according to ALV data table contents (instead of implementing set_description).

  • Hello Steve,

    I haven’t tried to do so, but I think, it would be possible. I’ll give a try and see..

    Regards,
    Naimesh Patel

  • Hello Shai,

    Thanks for the suggestions. I guess, we can achieve both of them. To achieve the first option, we would need to implement the object pool pattern. The responsibility than need to be transferred to the class who controls and keep tracks of the buttons.

    I would try to research on them and see hot it goes. Thanks for the ideas.

    Regards,
    Naimesh Patel

Comments on this Post are now closed. If you have something important to share, you can always contact me.

You seem to be new here. Subscribe to stay connected.