Копание в данных SAP

    В качестве промо-довеска к ранее опубликованной статье приложу немного опыта и исходного кода для специфической аудитории, а именно пользователей SAP. Однажды мне пришлось полгода позаниматься изучением и программированием в этой чудесной системе, а точнее в модуле CRM. Поскольку, с одной стороны, средства для броузинга данных в SAP крайне скудны, а, с другой, я был избалован собственными привычками делать все мышкой, однажды от скуки я занялся любимым делом — «Свободой выборки», но в ABAP & light версии.
    В SAPе таблиц какие-то жуткие тысячи штук, а названия у них не самые удобные и очевидные. Нормализация присутствует в изобилии. Поэтому понять, что же лежит в этой записи таблицы, скажем, BUT_000, можно лишь с некоторой натяжкой. Недолго думая, используя богатые средства рефлексии и метапрограммирования древнего как мамонт языка ABAP и сдабривая это всеми любимым alv_grid'ом я «слабал» некий код, позволяющий просматривать значения ссылок едва ли не на любую глубину, используя метаданные связей.
    На память, интерфейс z-отчета это не про кассы, о, случайно зашедший! следующий:
    • имя стартовой таблицы
    • дополнительное условие ограничения
    • количество строк
    В открывшемся гриде, равно как и во вложенных, двойной клик по «ссылочному» полю проваливается в таблицу. Остальное уже забыл, не исключено, что это не все вкусности.Изучайте, внедряйте рефакторите, надеюсь вы сможете сами. Удачи!
    Итак, исходный код на ABAP
    *&---------------------------------------------------------------------*
    *& Report  Z_GREAT_ALV_TMP
    *&
    *&---------------------------------------------------------------------*
    *&
    *&
    *&---------------------------------------------------------------------*
    
    REPORT  z_great_alv_tmp.
    
    DATA:
          gv_ok             LIKE sy-ucomm,
          gv_container      TYPE REF TO cl_gui_custom_container,
          gv_container_name TYPE scrfname VALUE 'CONTAINER_ALV',
          gv_grid           TYPE REF TO cl_gui_alv_grid,
          gt_fieldcat       TYPE lvc_t_fcat,
          gs_layout         TYPE lvc_s_layo.
    
    *&---------------------------------------------------------------------*
    *&  Include           Z_GREAT_ALV_F01
    *&---------------------------------------------------------------------*
    
    FORM create_alv
      USING
          container_name TYPE scrfname
      CHANGING
          container TYPE REF TO cl_gui_custom_container
          grid TYPE REF TO cl_gui_alv_grid.
      "если грида еще нет
      IF container IS NOT BOUND.
    
        "создать контейнер
        CREATE OBJECT container
          EXPORTING
            container_name = container_name
          EXCEPTIONS
            OTHERS         = 1.
        IF sy-subrc NE 0.
        ENDIF.
    
      ENDIF.
    
      IF container IS BOUND.
        "создать грид
    *    if grid is bound.
    *      free grid.
    *    endif.
    
        IF grid IS NOT BOUND.
          CREATE OBJECT grid
            EXPORTING
              i_parent = container
            EXCEPTIONS
              OTHERS   = 1.
          PERFORM set_great_handler.
        ENDIF.
    
        IF sy-subrc NE 0.
        ENDIF.
    
      ENDIF.
    
    ENDFORM.                    "create_alv
    
    *&---------------------------------------------------------------------*
    *&      Form  set_great_handlers
    *&---------------------------------------------------------------------*
    *       text
    *----------------------------------------------------------------------*
    
    *&---------------------------------------------------------------------*
    *&      Form  display_alv
    *&---------------------------------------------------------------------*
    *       text
    *----------------------------------------------------------------------*
    *      -->GRID       text
    *      -->TAB        text
    *----------------------------------------------------------------------*
    FORM display_alv
      CHANGING
            grid TYPE REF TO cl_gui_alv_grid
            tab TYPE ANY TABLE.
    
      IF grid IS BOUND.
        "заполнить свойства колонок
    *    PERFORM prepare_field_catalog CHANGING gt_fieldcat.
    *
        "главный метод для показа грида
        CALL METHOD grid->set_table_for_first_display
          EXPORTING" i_structure_name = gv_tablename
            is_layout                     = gs_layout
          CHANGING
            it_outtab                     = tab
            it_fieldcatalog               = gt_fieldcat
          EXCEPTIONS
            invalid_parameter_combination = 1
            program_error                 = 2
            too_many_lines                = 3
            OTHERS                        = 4.
        IF sy-subrc NE 0.
        ENDIF.
    
    *    "обновить данные
    *    CALL METHOD grid->refresh_table_display
    *      EXCEPTIONS
    *        finished       = 1
    *        OTHERS         = 2.
    *
    *    IF sy-subrc NE 0.
    *    ENDIF.
    
      ENDIF.
    
    ENDFORM.                    "display_alv
    
    *&---------------------------------------------------------------------*
    *&      Form  prepare_field_catalog
    *&---------------------------------------------------------------------*
    *       text
    *----------------------------------------------------------------------*
    *      -->PT_FIELDCAT  text
    *----------------------------------------------------------------------*
    FORM prepare_field_catalog
      USING
        tabname TYPE dd02l-tabname
        itab TYPE rs_bool
      CHANGING
        fieldcat TYPE lvc_t_fcat .
    
      REFRESH fieldcat.
    
      IF itab IS INITIAL.
        CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
          EXPORTING
            i_structure_name = tabname
          CHANGING
            ct_fieldcat      = fieldcat
          EXCEPTIONS
            OTHERS           = 1.
        FIELD-SYMBOLS: <fs_fcat> TYPE lvc_s_fcat.
        LOOP AT fieldcat ASSIGNING <fs_fcat>.
          <fs_fcat>-edit = 'X'.
        ENDLOOP.
      ELSE.
        DATA: lv_field TYPE lvc_s_fcat.
    
        lv_field-fieldname = 'FK_TABNAME'.
        lv_field-scrtext_s = 'TABNAME'.
        lv_field-inttype = 'C'.
        lv_field-outputlen = 50.
        APPEND lv_field TO fieldcat.
    
        lv_field-fieldname = 'FIELDNAME'.
        lv_field-scrtext_s = 'FIELDNAME'.
        lv_field-outputlen = 30.
        APPEND lv_field TO fieldcat.
    
      ENDIF.
      IF sy-subrc <> 0.
    * MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
    *         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
      ENDIF.
    
    
    ENDFORM.                    "prepare_field_catalog
    
    *&---------------------------------------------------------------------*
    *&      Form  great_alv
    *&---------------------------------------------------------------------*
    *       text
    *----------------------------------------------------------------------*
    
    *&---------------------------------------------------------------------*
    *&  Include           Z_GREAT_ALV_CL_DICTSERVICES
    *&---------------------------------------------------------------------*
    
    CLASS z_cl_great_alv_dictservices DEFINITION.
      PUBLIC SECTION.
        TYPES:
          BEGIN OF z_fk_pair,
            pk_name TYPE dd03l-fieldname,
            fk_name TYPE dd03l-fieldname,
          END OF z_fk_pair,
          z_fk_pair_list TYPE STANDARD TABLE OF z_fk_pair,
          BEGIN OF z_dependent_rec,
            pk_tabname TYPE dd02l-tabname,
            fk_tabname TYPE dd02l-tabname,
            fieldname TYPE dd03l-fieldname,
            frkart TYPE dd08l-frkart,
            fieldlist TYPE REF TO data,"z_fk_pair_list,
          END OF z_dependent_rec,
          z_dependent_rec_list TYPE STANDARD TABLE OF z_dependent_rec.
        CLASS-METHODS:
          get_fk_list
            IMPORTING
              tabname TYPE dd02l-tabname
              fieldname TYPE dd03l-fieldname
            EXPORTING
              dependent_rec TYPE z_dependent_rec,
          get_check_fk_list
            IMPORTING
              tabname TYPE dd02l-tabname
              fieldname TYPE dd03l-fieldname
            EXPORTING
              dependent_rec TYPE z_dependent_rec,
          get_dependent_list
            IMPORTING
              tabname TYPE dd02l-tabname
            EXPORTING
              tablist TYPE z_dependent_rec_list.
    ENDCLASS.                    "z_cl_great_alv_dictservices DEFINITION
    
    *----------------------------------------------------------------------*
    *       CLASS z_cl_great_alv_dictservices IMPLEMENTATION
    *----------------------------------------------------------------------*
    *
    *----------------------------------------------------------------------*
    CLASS z_cl_great_alv_dictservices IMPLEMENTATION.
      METHOD get_fk_list.
    
        dependent_rec-fk_tabname = tabname.
        dependent_rec-fieldname = fieldname.
    
        SELECT SINGLE checktable frkart FROM dd08l INTO (dependent_rec-pk_tabname, dependent_rec-frkart) WHERE tabname = tabname AND fieldname = fieldname.
        IF sy-subrc = 0 AND dependent_rec-pk_tabname <> '*'.
    
          DATA: ls_fk_pair TYPE z_fk_pair,
                lv_primpos TYPE dd05s-primpos.
          FIELD-SYMBOLS: <fs_pair_list> TYPE z_fk_pair_list.
          CREATE DATA dependent_rec-fieldlist TYPE z_fk_pair_list.
          ASSIGN dependent_rec-fieldlist->* TO <fs_pair_list>.
    
          SELECT primpos forkey FROM dd05s INTO (lv_primpos, ls_fk_pair-fk_name) WHERE tabname = tabname AND fieldname = fieldname.
            SELECT SINGLE fieldname FROM dd03l INTO ls_fk_pair-pk_name WHERE tabname = dependent_rec-pk_tabname AND position = lv_primpos.
            IF sy-subrc = 0.
              APPEND ls_fk_pair TO <fs_pair_list>.
            ENDIF.
          ENDSELECT.
    
        ENDIF.
    
      ENDMETHOD.                    "get_fk_list
    
      METHOD get_check_fk_list.
        dependent_rec-fk_tabname = tabname.
        dependent_rec-fieldname = fieldname.
    
        DATA: lv_domname TYPE dd03l-domname.
        SELECT SINGLE domname FROM dd03l INTO lv_domname WHERE tabname = tabname AND fieldname = fieldname.
        IF sy-subrc = 0 AND lv_domname IS NOT INITIAL.
    
          SELECT SINGLE entitytab FROM dd01l INTO dependent_rec-pk_tabname WHERE domname = lv_domname.
          IF sy-subrc = 0 AND dependent_rec-pk_tabname IS NOT INITIAL.
    
            DATA: ls_fk_pair TYPE z_fk_pair.
            FIELD-SYMBOLS: <fs_pair_list> TYPE z_fk_pair_list.
            CREATE DATA dependent_rec-fieldlist TYPE z_fk_pair_list.
            ASSIGN dependent_rec-fieldlist->* TO <fs_pair_list>.
    
            SELECT SINGLE fieldname FROM dd03l INTO ls_fk_pair-pk_name WHERE tabname = dependent_rec-pk_tabname AND domname = lv_domname AND keyflag = 'X'.
            IF sy-subrc = 0.
              ls_fk_pair-fk_name = fieldname.
              APPEND ls_fk_pair TO <fs_pair_list>.
            ENDIF.
    
          ENDIF.
        ENDIF.
      ENDMETHOD.                    "get_check_fk_list
    
      METHOD get_dependent_list.
        DATA: ls_rec TYPE z_dependent_rec.
        REFRESH tablist.
        SELECT tabname fieldname frkart FROM dd08l INTO (ls_rec-fk_tabname, ls_rec-fieldname, ls_rec-frkart) WHERE checktable = tabname.
          get_fk_list( EXPORTING
            tabname = ls_rec-fk_tabname
            fieldname = ls_rec-fieldname
          IMPORTING
            dependent_rec = ls_rec ).
          IF ls_rec-fieldlist IS BOUND.
            APPEND ls_rec TO tablist.
            CLEAR ls_rec.
          ENDIF.
        ENDSELECT.
      ENDMETHOD.                    "get_dependent_list
    ENDCLASS.                    "z_cl_great_alv_dictservices IMPLEMENTATION
    
    ** METHOD forward_zalx.
    **    DATA:
    **          lv_rowtype TYPE zalx_clnt_genfld-rowtype,
    **          lv_fkrowtype TYPE zalx_clnt_genfld-fkrowtype,
    **          lv_fkrowpos TYPE zalx_clnt_genfld-fkrowpos,
    **          lv_structname TYPE zalx_clnt_genrel-structname,
    **          lv_tablename TYPE dd02l-tabname,
    **          lv_condition TYPE string,
    **          ls_nav_point TYPE z_nav_point.
    **    READ TABLE nav_stack INTO ls_nav_point INDEX nav_position.
    **    ls_nav_point-row_id = row_id.
    **    ls_nav_point-key_field = fieldname.
    **    MODIFY nav_stack INDEX nav_position FROM ls_nav_point.
    **
    **    IF sy-subrc = 0.
    **      SELECT SINGLE rowtype FROM zalx_clnt_genrel INTO lv_rowtype WHERE structname = ls_nav_point-tab_name.
    **      IF sy-subrc = 0.
    **        SELECT SINGLE fkrowtype fkrowpos FROM zalx_clnt_genfld INTO (lv_fkrowtype, lv_fkrowpos) WHERE rowtype = lv_rowtype AND fieldname = fieldname.
    **        IF sy-subrc = 0.
    **          SELECT SINGLE structname FROM zalx_clnt_genrel INTO lv_structname WHERE rowtype = lv_fkrowtype.
    **          IF sy-subrc = 0.
    **
    **            table_name = lv_structname.
    **            SELECT SINGLE fieldname FROM zalx_clnt_genfld INTO lv_condition WHERE rowtype = lv_fkrowtype AND rowpos = lv_fkrowpos.
    **            IF sy-subrc  = 0.
    **              WRITE lv_structname.
    **              FIELD-SYMBOLS: <ff> TYPE ANY,
    **                             <fs> TYPE ANY,
    **                             <lfs_table> TYPE STANDARD TABLE.
    **
    **              ASSIGN ls_nav_point-tab_table->* TO <lfs_table>.
    **              READ TABLE <lfs_table> ASSIGNING <fs> INDEX row_id-row_id.
    **              ASSIGN COMPONENT fieldname OF STRUCTURE <fs> TO <ff>.
    **              CONCATENATE lv_condition ' = ''' <ff> '''' INTO lv_condition.
    **
    **              CLEAR ls_nav_point.
    **
    **              lv_tablename = lv_structname.
    **              doselect( EXPORTING tablename = lv_tablename condition = lv_condition
    **                IMPORTING data_table = ls_nav_point-tab_table ).
    **
    **              data_table = ls_nav_point-tab_table.
    **              ls_nav_point-tab_name = lv_structname.
    **
    **              APPEND ls_nav_point TO nav_stack.
    **              ADD 1 TO nav_position.
    **
    **            ENDIF.
    **
    **          ENDIF.
    **
    **        ENDIF.
    **      ENDIF.
    **    ENDIF.
    **
    **  ENDMETHOD.                    "forward
    *&---------------------------------------------------------------------*
    *&  Include           Z_GREAT_ALV_CL
    *&---------------------------------------------------------------------*
    
    *&---------------------------------------------------------------------*
    *&  Include           Z_GREAT_ALV_CL_NAVSTACK
    *&---------------------------------------------------------------------*
    
    CLASS z_cl_great_alv_navstack DEFINITION.
      PUBLIC SECTION.
        TYPES:
          BEGIN OF z_nav_point,
            tab_name TYPE dd02l-tabname,
            key_field TYPE lvc_s_col,
            row_id TYPE lvc_s_roid,
            tab_table TYPE REF TO data,
            dependent TYPE rs_bool,
          END OF z_nav_point.
        CLASS-METHODS:
          init
            IMPORTING
              tablename TYPE dd02l-tabname
              reccount TYPE i
              condition TYPE string
            RETURNING
              value(ok) TYPE rs_bool,
          follow_fk
            IMPORTING
              fieldname TYPE lvc_s_col
              row_id TYPE lvc_s_roid
            RETURNING
              value(ok) TYPE rs_bool,
          choose_dependent
            IMPORTING
              fieldname TYPE lvc_s_col
              row_id TYPE lvc_s_roid
              table_name TYPE dd02l-tabname OPTIONAL
            RETURNING
              value(ok) TYPE rs_bool,
          follow_pk
            IMPORTING
              deprec TYPE z_cl_great_alv_dictservices=>z_dependent_rec
              row_id TYPE lvc_s_roid
            RETURNING
              value(ok) TYPE rs_bool,
          follow_text
            IMPORTING
              row_id TYPE lvc_s_roid
            RETURNING
              value(ok) TYPE rs_bool,
          back,
          current_nav_point RETURNING
            value(point) TYPE z_nav_point,
          follow_zalx
            IMPORTING
              fieldname TYPE lvc_s_col
              row_id TYPE lvc_s_roid
            RETURNING
              value(ok) TYPE rs_bool,
          get_condition_string IMPORTING
            row_id TYPE i
            deprec TYPE z_cl_great_alv_dictservices=>z_dependent_rec
            data_table TYPE REF TO data OPTIONAL
            dependent TYPE rs_bool OPTIONAL
            RETURNING value(condition) TYPE string.
    
    
      PRIVATE SECTION.
        CLASS-DATA:
          nav_stack TYPE TABLE OF z_nav_point,
          nav_position TYPE i,
          rec_count TYPE i.
        CLASS-METHODS:
          doselect
            IMPORTING
              tablename TYPE dd02l-tabname
              condition TYPE string OPTIONAL
            EXPORTING
              data_table TYPE REF TO data.
    
    ENDCLASS.                    "Z_CL_GREAT_ALV_NAVSTACK DEFINITION
    
    *----------------------------------------------------------------------*
    *       CLASS Z_CL_GREAT_ALV_NAVSTACK IMPLEMENTATION
    *----------------------------------------------------------------------*
    *
    *----------------------------------------------------------------------*
    CLASS z_cl_great_alv_navstack IMPLEMENTATION.
      METHOD init.
        REFRESH: nav_stack.
        DATA:  ls_nav_point TYPE z_nav_point.
        rec_count = reccount.
    
        doselect( EXPORTING tablename = tablename condition = condition
          IMPORTING data_table = ls_nav_point-tab_table ).
    
        IF ls_nav_point-tab_table IS BOUND.
          ls_nav_point-tab_name = tablename.
          APPEND ls_nav_point TO nav_stack.
          nav_position = 1.
          ok = 'X'.
        ENDIF.
    
      ENDMETHOD.                    "init
    
      METHOD doselect.
        CREATE DATA data_table TYPE TABLE OF (tablename).
        FIELD-SYMBOLS: <fsv_table> TYPE STANDARD TABLE.
        ASSIGN data_table->* TO <fsv_table>.
    
        IF condition IS SUPPLIED.
          SELECT * UP TO rec_count ROWS FROM (tablename) INTO TABLE <fsv_table> WHERE (condition).
        ELSE.
          SELECT * UP TO rec_count ROWS FROM (tablename) INTO TABLE <fsv_table>.
        ENDIF.
      ENDMETHOD.                    "doselect
    
    
      METHOD follow_fk.
    
        DATA: ls_dep TYPE z_cl_great_alv_dictservices=>z_dependent_rec,
              ls_nav_point TYPE z_nav_point,
              lv_colname TYPE lvc_s_col,
              lv_condition TYPE string.
    
        ls_nav_point = current_nav_point( ).
        ls_nav_point-row_id = row_id.
        ls_nav_point-key_field = fieldname.
        MODIFY nav_stack INDEX nav_position FROM ls_nav_point.
    
        IF ls_nav_point-dependent IS INITIAL.
    
          z_cl_great_alv_dictservices=>get_fk_list( EXPORTING
              tabname = ls_nav_point-tab_name
              fieldname = fieldname-fieldname
            IMPORTING
              dependent_rec = ls_dep ).
    
          IF ls_dep-fieldlist IS NOT BOUND.
    
            z_cl_great_alv_dictservices=>get_check_fk_list( EXPORTING
                tabname = ls_nav_point-tab_name
                fieldname = fieldname-fieldname
              IMPORTING
                dependent_rec = ls_dep ).
    
          ENDIF.
    
          IF ls_dep-fieldlist IS BOUND.
    
            lv_condition = get_condition_string(
              row_id = row_id-row_id
              deprec = ls_dep ).
    
            CLEAR ls_nav_point.
    
            doselect( EXPORTING tablename = ls_dep-pk_tabname condition = lv_condition
              IMPORTING data_table = ls_nav_point-tab_table ).
    
            IF ls_nav_point-tab_table IS BOUND.
              ls_nav_point-tab_name = ls_dep-pk_tabname.
    
              APPEND ls_nav_point TO nav_stack.
              ADD 1 TO nav_position.
              ok = 'X'.
            ENDIF.
    
          ENDIF.
    
        ELSE.
    
          FIELD-SYMBOLS: <fs_dep> TYPE z_cl_great_alv_dictservices=>z_dependent_rec_list.
          ASSIGN ls_nav_point-tab_table->* TO <fs_dep>.
          IF <fs_dep> IS ASSIGNED.
            READ TABLE <fs_dep> INTO ls_dep INDEX row_id-row_id.
            IF sy-subrc = 0.
              back( ).
              ls_nav_point = current_nav_point( ).
              lv_colname-fieldname = ls_dep-fieldname.
              ok = follow_pk( deprec = ls_dep
                row_id = ls_nav_point-row_id
                 ).
            ENDIF.
          ENDIF.
    
        ENDIF.
    
      ENDMETHOD.                    "follow_fk
    
      METHOD choose_dependent.
        DATA: ls_nav_point TYPE z_nav_point,
              lv_dep_list TYPE REF TO data.
        FIELD-SYMBOLS <fs_deplist> TYPE z_cl_great_alv_dictservices=>z_dependent_rec_list.
        ls_nav_point = current_nav_point( ).
        ls_nav_point-row_id = row_id.
        ls_nav_point-key_field = fieldname.
        MODIFY nav_stack INDEX nav_position FROM ls_nav_point.
    
        CREATE DATA lv_dep_list TYPE z_cl_great_alv_dictservices=>z_dependent_rec_list.
        ASSIGN lv_dep_list->* TO <fs_deplist>.
        z_cl_great_alv_dictservices=>get_dependent_list(
          EXPORTING
            tabname = ls_nav_point-tab_name
          IMPORTING
            tablist = <fs_deplist> ).
    
        IF lv_dep_list IS NOT INITIAL.
          SORT <fs_deplist>  BY fk_tabname ASCENDING.
          CLEAR ls_nav_point.
    
          ls_nav_point-tab_table = lv_dep_list.
          ls_nav_point-dependent = 'X'.
    
          APPEND ls_nav_point TO nav_stack.
          ADD 1 TO nav_position.
          ok = 'X'.
        ENDIF.
    
      ENDMETHOD.                    "choose_dependent
    
      METHOD follow_pk.
        DATA: lv_condition TYPE string,
              ls_nav_point TYPE z_nav_point.
    
        ls_nav_point = current_nav_point( ).
        ls_nav_point-row_id = row_id.
        MODIFY nav_stack INDEX nav_position FROM ls_nav_point.
    
        lv_condition = get_condition_string(
          row_id = row_id-row_id
          deprec = deprec
          dependent = 'X' ).
    
        CLEAR ls_nav_point.
    
        doselect( EXPORTING tablename = deprec-fk_tabname
          condition = lv_condition
          IMPORTING data_table = ls_nav_point-tab_table ).
    
        IF ls_nav_point-tab_table IS BOUND.
          ls_nav_point-tab_name = deprec-fk_tabname.
    
          APPEND ls_nav_point TO nav_stack.
          ADD 1 TO nav_position.
          ok = 'X'.
        ENDIF.
      ENDMETHOD.                    "follow_pk
    
      METHOD follow_text.
        DATA: ls_nav_point TYPE z_nav_point,
              lv_colname TYPE lvc_s_col,
              lt_dep_list TYPE z_cl_great_alv_dictservices=>z_dependent_rec_list,
              ls_dep_list TYPE LINE OF z_cl_great_alv_dictservices=>z_dependent_rec_list.
        ls_nav_point = current_nav_point( ).
        z_cl_great_alv_dictservices=>get_dependent_list(
          EXPORTING
            tabname = ls_nav_point-tab_name
          IMPORTING
            tablist = lt_dep_list ).
    
        LOOP AT lt_dep_list INTO ls_dep_list WHERE frkart = 'TEXT'.
          lv_colname-fieldname = ls_dep_list-fieldname.
          ok = follow_pk( deprec = ls_dep_list
            row_id = row_id
             ).
          EXIT. "only one text table, if any
        ENDLOOP.
    
      ENDMETHOD.                    "follow_text
    
      METHOD back.
        IF nav_position > 1.
          DELETE nav_stack INDEX nav_position.
          SUBTRACT 1 FROM nav_position.
        ENDIF.
      ENDMETHOD.                    "back
    
      METHOD current_nav_point.
        READ TABLE nav_stack INTO point INDEX nav_position.
      ENDMETHOD.                    "current_table_name
    
      METHOD get_condition_string.
    
        FIELD-SYMBOLS: <ff> TYPE ANY,
                       <fs> TYPE ANY,
                       <lfs_table> TYPE STANDARD TABLE,
                       <lfs_fkrec> TYPE z_cl_great_alv_dictservices=>z_fk_pair_list.
        DATA: ls_navpoint TYPE z_nav_point,
              ls_fkpair TYPE z_cl_great_alv_dictservices=>z_fk_pair,
              lv_condition TYPE string,
              lt_condition TYPE TABLE OF string.
        ls_navpoint = current_nav_point( ).
        ASSIGN ls_navpoint-tab_table->* TO <lfs_table>.
        READ TABLE <lfs_table> ASSIGNING <fs> INDEX row_id.
    
        ASSIGN deprec-fieldlist->* TO <lfs_fkrec>.
        LOOP AT <lfs_fkrec> INTO ls_fkpair.
          IF dependent IS INITIAL.
            ASSIGN COMPONENT ls_fkpair-fk_name OF STRUCTURE <fs> TO <ff>.
            CONCATENATE ls_fkpair-pk_name ' = ''' <ff> '''' INTO lv_condition.
          ELSE.
            ASSIGN COMPONENT ls_fkpair-pk_name OF STRUCTURE <fs> TO <ff>.
            CONCATENATE ls_fkpair-fk_name ' = ''' <ff> '''' INTO lv_condition.
          ENDIF.
          APPEND lv_condition TO lt_condition.
        ENDLOOP.
    
        CONCATENATE LINES OF lt_condition INTO condition SEPARATED BY ' AND '.
    
      ENDMETHOD.                    "get_condition_string
    
    
      METHOD follow_zalx.
        DATA:
              lv_rowtype TYPE zalx_clnt_genfld-rowtype,
              lv_fkrowtype TYPE zalx_clnt_genfld-fkrowtype,
              lv_fkrowpos TYPE zalx_clnt_genfld-fkrowpos,
              lv_structname TYPE zalx_clnt_genrel-structname,
              lv_tablename TYPE dd02l-tabname,
              lv_condition TYPE string,
              ls_nav_point TYPE z_nav_point.
        READ TABLE nav_stack INTO ls_nav_point INDEX nav_position.
        ls_nav_point-row_id = row_id.
        ls_nav_point-key_field = fieldname.
        MODIFY nav_stack INDEX nav_position FROM ls_nav_point.
    
        IF sy-subrc = 0.
          SELECT SINGLE rowtype FROM zalx_clnt_genrel INTO lv_rowtype WHERE structname = ls_nav_point-tab_name.
          IF sy-subrc = 0.
            SELECT SINGLE fkrowtype fkrowpos FROM zalx_clnt_genfld INTO (lv_fkrowtype, lv_fkrowpos) WHERE rowtype = lv_rowtype AND fieldname = fieldname.
            IF sy-subrc = 0.
              SELECT SINGLE structname FROM zalx_clnt_genrel INTO lv_structname WHERE rowtype = lv_fkrowtype.
              IF sy-subrc = 0.
    
                "table_name = lv_structname.
                SELECT SINGLE fieldname FROM zalx_clnt_genfld INTO lv_condition WHERE rowtype = lv_fkrowtype AND rowpos = lv_fkrowpos.
                IF sy-subrc  = 0.
                  WRITE lv_structname.
                  FIELD-SYMBOLS: <ff> TYPE ANY,
                                 <fs> TYPE ANY,
                                 <lfs_table> TYPE STANDARD TABLE.
    
                  ASSIGN ls_nav_point-tab_table->* TO <lfs_table>.
                  READ TABLE <lfs_table> ASSIGNING <fs> INDEX row_id-row_id.
                  ASSIGN COMPONENT fieldname OF STRUCTURE <fs> TO <ff>.
                  CONCATENATE lv_condition ' = ''' <ff> '''' INTO lv_condition.
    
                  CLEAR ls_nav_point.
    
                  lv_tablename = lv_structname.
                  doselect( EXPORTING tablename = lv_tablename condition = lv_condition
                    IMPORTING data_table = ls_nav_point-tab_table ).
    
                  IF ls_nav_point-tab_table IS BOUND.
                    ls_nav_point-tab_name = lv_structname.
    
                    APPEND ls_nav_point TO nav_stack.
                    ADD 1 TO nav_position.
                    ok = 'X'.
                  ENDIF.
    
                ENDIF.
    
              ENDIF.
    
            ENDIF.
          ENDIF.
        ENDIF.
    
      ENDMETHOD.                    "forward
    ENDCLASS.                    "Z_CL_GREAT_ALV_NAVSTACK IMPLEMENTATION
    
    *----------------------------------------------------------------------*
    *       CLASS z_great_alv_handler DEFINITION
    *----------------------------------------------------------------------*
    *
    *----------------------------------------------------------------------*
    CLASS z_great_alv_handler DEFINITION.
      PUBLIC SECTION.
        CLASS-DATA:
          zf_texting TYPE stb_button-function VALUE 'TEXTING',
          zf_zalx TYPE stb_button-function VALUE 'ZALX',
          zf_depend TYPE stb_button-function VALUE 'DEPEND',
          zf_follow TYPE stb_button-function VALUE 'FOLLOW'.
        METHODS:
          double_click FOR EVENT double_click OF cl_gui_alv_grid
            IMPORTING e_row e_column es_row_no,
          toolbar_modify FOR EVENT toolbar OF cl_gui_alv_grid
            IMPORTING e_object e_interactive,
          user_command FOR EVENT user_command OF cl_gui_alv_grid
            IMPORTING e_ucomm,
          data_changed FOR EVENT data_changed OF cl_gui_alv_grid
            IMPORTING er_data_changed e_onf4 e_onf4_before e_onf4_after e_ucomm.
    ENDCLASS.                    "Z_GREAT_ALV_HANDLER DEFINITION
    
    *----------------------------------------------------------------------*
    *       CLASS Z_GREAT_ALV_HANDLER IMPLEMENTATION
    *----------------------------------------------------------------------*
    *
    *----------------------------------------------------------------------*
    CLASS z_great_alv_handler IMPLEMENTATION.
      METHOD double_click.
        DATA: lv_ok TYPE rs_bool.
        lv_ok = z_cl_great_alv_navstack=>follow_fk(
          fieldname = e_column
          row_id = es_row_no ).
    
        IF lv_ok = 'X'.
          CALL SCREEN 100.
        ENDIF.
    
      ENDMETHOD.                    "DOUBLE_CLICK
    
      METHOD toolbar_modify.
        DATA: lv_tbutton TYPE stb_button.
    
        LOOP AT e_object->mt_toolbar INTO lv_tbutton WHERE function = zf_texting.
        ENDLOOP.
    
        IF sy-subrc <> 0.
    
          CLEAR lv_tbutton.
          MOVE 0 TO lv_tbutton-butn_type.
          MOVE zf_follow TO lv_tbutton-function.
          MOVE 'Follow foreign key/check table' TO lv_tbutton-text.
          MOVE 'Follow foreign key/check table' TO lv_tbutton-quickinfo.
          MOVE space TO lv_tbutton-disabled.
    
          APPEND lv_tbutton TO e_object->mt_toolbar.
    
          CLEAR lv_tbutton.
          MOVE 0 TO lv_tbutton-butn_type.
          MOVE zf_texting TO lv_tbutton-function.
          MOVE 'Text table record' TO lv_tbutton-text.
          MOVE 'Text table record' TO lv_tbutton-quickinfo.
          MOVE space TO lv_tbutton-disabled.
    
          APPEND lv_tbutton TO e_object->mt_toolbar.
    
          CLEAR lv_tbutton.
          MOVE 0 TO lv_tbutton-butn_type.
          MOVE zf_depend TO lv_tbutton-function.
          MOVE 'Dependent tables' TO lv_tbutton-text.
          MOVE 'Dependent tables' TO lv_tbutton-quickinfo.
          MOVE space TO lv_tbutton-disabled.
    
          APPEND lv_tbutton TO e_object->mt_toolbar.
    
          CLEAR lv_tbutton.
          MOVE 0 TO lv_tbutton-butn_type.
          MOVE zf_zalx TO lv_tbutton-function.
          MOVE 'ZALX' TO lv_tbutton-text.
          MOVE 'ZALX' TO lv_tbutton-quickinfo.
          MOVE space TO lv_tbutton-disabled.
    
          APPEND lv_tbutton TO e_object->mt_toolbar.
    
        ENDIF.
    
      ENDMETHOD.                    "toolbar_modify
    
      METHOD user_command.
    
        DATA: lv_table  TYPE REF TO data,
              lv_column TYPE lvc_s_col,
              lv_rowno  TYPE lvc_s_roid,
              lv_ok     TYPE rs_bool.
        gv_grid->get_current_cell( IMPORTING es_col_id = lv_column
          es_row_no = lv_rowno ).
    
        CASE e_ucomm.
          WHEN zf_texting.
            lv_ok = z_cl_great_alv_navstack=>follow_text(
              row_id = lv_rowno ).
          WHEN zf_zalx.
            lv_ok = z_cl_great_alv_navstack=>follow_zalx(
            fieldname = lv_column
            row_id = lv_rowno ).
          WHEN zf_depend.
            lv_ok = z_cl_great_alv_navstack=>choose_dependent(
              fieldname = lv_column
              row_id = lv_rowno ).
          WHEN zf_follow.
            lv_ok = z_cl_great_alv_navstack=>follow_fk(
            fieldname = lv_column
            row_id = lv_rowno ).
          WHEN OTHERS.
            EXIT.
        ENDCASE.
    
        IF lv_ok = 'X'.
          CALL SCREEN 100.
        ENDIF.
    
      ENDMETHOD.                    "user_command
    
      METHOD data_changed.
        DATA: ls_nav_point TYPE z_cl_great_alv_navstack=>z_nav_point,
              ls_deleted_row TYPE lvc_s_moce.
        FIELD-SYMBOLS: <fst> TYPE STANDARD TABLE,
                       <fs> TYPE ANY.
        "modify
        ls_nav_point = z_cl_great_alv_navstack=>current_nav_point( ).
        ASSIGN er_data_changed->mp_mod_rows->* TO <fst>.
        MODIFY (ls_nav_point-tab_name) FROM TABLE <fst>.
    
        "delete
        ASSIGN ls_nav_point-tab_table->* TO <fst>.
        LOOP AT er_data_changed->mt_deleted_rows INTO ls_deleted_row.
          READ TABLE <fst> ASSIGNING <fs> INDEX ls_deleted_row-row_id.
          IF sy-subrc = 0.
            DELETE (ls_nav_point-tab_name) FROM <fs>.
          ENDIF.
        ENDLOOP.
    
      ENDMETHOD.                    "data_changed
    
    ENDCLASS.                    "Z_GREAT_ALV_HANDLER IMPLEMENTATION
    
    *----------------------------------------------------------------------*
    *  MODULE PAI_01 INPUT
    *----------------------------------------------------------------------*
    *
    *----------------------------------------------------------------------*
    MODULE pai_01 INPUT.
    
      CASE gv_ok.
        WHEN 'BACK'.
          z_cl_great_alv_navstack=>back( ).
          PERFORM great_alv.
        WHEN '%EX'.
          LEAVE PROGRAM.
      ENDCASE.
    
    ENDMODULE.                 " PAI_01  INPUT
    
    *----------------------------------------------------------------------*
    *  MODULE PBO_01 OUTPUT
    *----------------------------------------------------------------------*
    *
    *----------------------------------------------------------------------*
    MODULE pbo_01 OUTPUT.
    
      CLEAR gv_ok.
      SET PF-STATUS ''.
      PERFORM great_alv.
    
    ENDMODULE.                 " PBO_01  OUTPUT
    
    *&---------------------------------------------------------------------*
    *&      Form  set_great_handler
    *&---------------------------------------------------------------------*
    *       text
    *----------------------------------------------------------------------*
    FORM set_great_handler.
      DATA lv_handler TYPE REF TO z_great_alv_handler.
      CREATE OBJECT lv_handler.
      IF gv_grid IS BOUND AND lv_handler IS BOUND.
        SET HANDLER lv_handler->double_click FOR gv_grid.
        SET HANDLER lv_handler->toolbar_modify FOR gv_grid.
        SET HANDLER lv_handler->user_command FOR gv_grid.
        SET HANDLER lv_handler->data_changed FOR gv_grid.
        "grid->set_toolbar_interactive( ).
      ENDIF.
    ENDFORM.                    "set_great_handlers
    
    *&---------------------------------------------------------------------*
    *&      Form  great_alv
    *&---------------------------------------------------------------------*
    *       text
    *----------------------------------------------------------------------*
    FORM great_alv.
    
      DATA: lv_nav_point TYPE z_cl_great_alv_navstack=>z_nav_point.
    
      lv_nav_point = z_cl_great_alv_navstack=>current_nav_point( ).
    
      PERFORM create_alv USING gv_container_name CHANGING gv_container gv_grid.
      .
      PERFORM prepare_field_catalog USING lv_nav_point-tab_name lv_nav_point-dependent CHANGING gt_fieldcat.
    
      FIELD-SYMBOLS: <lfs_table> TYPE ANY TABLE.
      ASSIGN  lv_nav_point-tab_table->* TO <lfs_table>.
    
      PERFORM display_alv USING gv_grid <lfs_table>.
    
      gv_grid->set_current_cell_via_id( EXPORTING "is_row_no = lv_nav_point-row_id
         is_column_id = lv_nav_point-key_field
         is_row_no = lv_nav_point-row_id ).
    
    ENDFORM.                    "great_alv
    
    
    
    PARAMETERS: tabname LIKE dd02l-tabname DEFAULT 'but050',
                rccount TYPE i DEFAULT 100,
                condit TYPE string DEFAULT ''.
    
    START-OF-SELECTION.
    
      DATA: lv_ok TYPE rs_bool.
    
      lv_ok = z_cl_great_alv_navstack=>init(
          tablename = tabname
          reccount = rccount
          condition = condit
         ).
    
      IF lv_ok = 'X'.
        CALL SCREEN 100.
      ENDIF.
    
    
    
    • –5
    • 4,8k
    • 8
    Поделиться публикацией

    Комментарии 8

      0
      Ну дак выложите на github или еще куда. Удобнее же чем код из спойлера выковыривать.
        –6
        я не был в курсе ваших привычек и сожалею что они фатально сказались на пользе кода для вас лично
          0
          Позор
            –1
            И много вы саповского кода на гитхабе разместили/скачали?
              0
              Я много разного кода на Github разместил, и еще больше — скачал.
                –3
                И саповского тоже? Ну расскажите тогда на черта сапу гитхаб?
                  +1
                  Попробуйте сначала выделить и скопировать весь ваш кусок кода, а потом попробуйте нажать на гитхабе Raw, Ctrl-A, Ctrl-C, желательно с секундомером.
            +1
            Это был дружеский совет, не хотите, не выкладывайте. С моими привычками это никак не связано, только с удобством для тех, кто заинтересуется вашим кодом.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое