Flexible Erzeugung des Feldkataloges

In dem Artikel DATA … RENAMING WITH SUFFIX macht Enno die Aussage “Die ALVs haben Probleme mit komplexen Strukturen”. Das stimmt so nicht. Natürlich ist es kein Problem des ALV sondern ein Problem bei der Erzeugung des Feldkatalogs. Ich habe mich deswegen einmal um die Erzeugung des Feldkatalogs zu einer komplexen Struktur gekümmert und ein Programm entwickelt, dass einen Feldkatalog zu einer tiefen Struktur aufbauen kann.

Arbeitsweise

Das Programm analysiert die komplexe Datenstruktur einer internen Tabelle und baut den Feldkatalog so auf, dass der ALV ihn zur Anzeige der Daten verwenden kann.

Die Anzeige ist etwas bunter ausgefallen… 😉

Bild_2014_06_23_180623

Coding

REPORT .

TYPES: BEGIN OF gts_data,
*         mara TYPE mara,
*         marc TYPE marc,
         t005  TYPE t005,
         t005t TYPE t005t,
       END OF gts_data.


DATA gt_data     TYPE STANDARD TABLE OF gts_data WITH NON-UNIQUE DEFAULT KEY.
DATA gt_fieldcat TYPE lvc_t_fcat.
DATA go_grid     TYPE REF TO cl_gui_alv_grid.
DATA gv_style    TYPE i.

*----------------------------------------------------------------------*
*       CLASS lcx_general_exceptions DEFINITION
*----------------------------------------------------------------------*
CLASS lcx_general_exceptions DEFINITION INHERITING FROM cx_static_check.
ENDCLASS.                    "lcx_general_exceptions DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_alv_utilities DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_alv_utilities DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS create_fieldcat_lvc  IMPORTING i_data TYPE  any
                                       RETURNING value(et_fieldcat) TYPE lvc_t_fcat
                                       RAISING lcx_general_exceptions.
  PRIVATE SECTION.
    CLASS-METHODS create_fieldcat_line IMPORTING i_data TYPE  any
                                       RETURNING value(et_fieldcat) TYPE lvc_t_fcat.
ENDCLASS.                    "lcl_alv_utilities DEFINITION


START-OF-SELECTION.
  WRITE '.'.

  SELECT * UP TO 100 ROWS
    INTO TABLE gt_data
*    FROM mara JOIN marc ON mara~matnr = marc~matnr.
    FROM t005 JOIN t005t ON t005~land1 = t005t~land1.

  CREATE OBJECT go_grid
    EXPORTING
      i_parent = cl_gui_container=>screen0.
  gt_fieldcat = lcl_alv_utilities=>create_fieldcat_lvc( gt_data ).
  go_grid->set_table_for_first_display( CHANGING
                                          it_outtab       = gt_data
                                          it_fieldcatalog = gt_fieldcat ).

*----------------------------------------------------------------------*
*       CLASS lcl_alv_utilities IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_alv_utilities IMPLEMENTATION.

  METHOD create_fieldcat_lvc.

    FIELD-SYMBOLS: <lt_data> TYPE ANY TABLE,
                   <ls_line> TYPE any,
                   <ls_dref> TYPE any.

    DATA lr_dref                 TYPE REF TO data.
    data lo_descr                TYPE REF TO cl_abap_typedescr.
    data lo_structdescr          TYPE REF TO cl_abap_structdescr.
    DATA lt_components           TYPE cl_abap_structdescr=>component_table.
    FIELD-SYMBOLS <ls_component> LIKE LINE OF lt_components.

    lo_descr = cl_abap_typedescr=>describe_by_data( i_data ).

    CASE lo_descr->kind.

      WHEN cl_abap_typedescr=>kind_elem.                   
" Special case.  We see this when we have something like 
"... type standard table of syucomm.
* Tried various things but Grid won't show anything - 
" no matter what I try to provide a faked fieldcat
        RAISE EXCEPTION TYPE lcx_general_exceptions.       " Not foreseen yet

      WHEN cl_abap_typedescr=>kind_struct.                 
        " Structure is fine --> create fieldcat from this
        et_fieldcat = create_fieldcat_line( i_data ).

      WHEN cl_abap_typedescr=>kind_table.                  
        " Table --> restart with linetype of table
        ASSIGN i_data TO <lt_data>.
        CREATE DATA lr_dref LIKE LINE OF <lt_data>.
        ASSIGN lr_dref->* TO <ls_line>.
        et_fieldcat = create_fieldcat_lvc( <ls_line> ).

      WHEN cl_abap_typedescr=>kind_ref.                    
        " Reference --> restart with dereferenced value
        ASSIGN i_data->* TO <ls_dref>.
        et_fieldcat = create_fieldcat_lvc( <ls_dref> ).

*    when cl_abap_typedescr=>KIND_CLASS.
*    when cl_abap_typedescr=>KIND_INTF  .
      WHEN OTHERS.
        BREAK-POINT.  " Ich will das vorher sehen
        RAISE EXCEPTION TYPE lcx_general_exceptions.       " Not foreseen yet

    ENDCASE.

  ENDMETHOD.                                               "create_fieldcat_lvc


  METHOD create_fieldcat_line.

    DATA lr_dref               TYPE REF TO data.
    data lo_salv               TYPE REF TO cl_salv_table.
    data lo_salv_columns_table TYPE REF TO cl_salv_columns_table.
    data lo_salv_aggregations  TYPE REF TO cl_salv_aggregations.
    data lv_help_id            TYPE string.

    FIELD-SYMBOLS <ls_fc>      LIKE LINE OF et_fieldcat.
    FIELD-SYMBOLS <lv_field>   TYPE any.

    FIELD-SYMBOLS <lt_data>    TYPE STANDARD TABLE.

*--------------------------------------------------------------------*
* Create standard table of input
*--------------------------------------------------------------------*
    CREATE DATA lr_dref LIKE STANDARD TABLE OF i_data.
    ASSIGN lr_dref->* TO <lt_data>.
    TRY.
        cl_salv_table=>factory( IMPORTING
                                  r_salv_table   = lo_salv
                                CHANGING
                                  t_table        = <lt_data> ).
        lo_salv_columns_table = lo_salv->get_columns( ).
        lo_salv_aggregations  = lo_salv->get_aggregations( ).

        et_fieldcat = cl_salv_controller_metadata=>get_lvc_fieldcatalog(
                            r_columns      = lo_salv_columns_table
                            r_aggregations = lo_salv_aggregations ).
*--------------------------------------------------------------------*
* Internal fields w/o descriptions --> set fieldname into header line
*--------------------------------------------------------------------*
        LOOP AT et_fieldcat ASSIGNING <ls_fc> WHERE scrtext_s = space
                                                AND scrtext_m = space
                                                AND scrtext_l = space.
          <ls_fc>-scrtext_m = <ls_fc>-fieldname.
        ENDLOOP.

*--------------------------------------------------------------------*
* Add F1 and F4-Help
* Idea from http://wiki.scn.sap.com/wiki/display/Snippets/ALV+fieldcatalog+-+create+for+ANY+table
*--------------------------------------------------------------------*
        LOOP AT et_fieldcat ASSIGNING <ls_fc>.

          ASSIGN COMPONENT <ls_fc>-fieldname OF STRUCTURE i_data TO <lv_field>.
          CHECK sy-subrc = 0.
          <ls_fc>-style     = gv_style.
          ADD 1 TO gv_style.

        TRY.
          CLEAR lv_help_id.
          DESCRIBE FIELD <lv_field> HELP-ID lv_help_id.
          IF lv_help_id CA '-'.
            SPLIT lv_help_id AT '-' INTO <ls_fc>-ref_table <ls_fc>-ref_field.
          ENDIF.
          CATCH cx_root.
        ENDTRY.

        ENDLOOP.

      CATCH cx_salv_msg .
    ENDTRY.

  ENDMETHOD.                                               "create_fieldcat_line
ENDCLASS.                    "lcl_alv_utilities IMPLEMENTATION