REPORT z_alv_modify_pid.
***********************************************************************
* ALV Grid Control                                                    *
* This program lists the user's Parameter-IDs, These Parameter-IDs    *
* can be modified and saved via Batch-Input                           *
*---------------------------------------------------------------------*
* Steps :                                                             *
* - Create the report Z_ALV_MODIFY_PID                                *
* - Create the Dynpro 0100 (size 27x120)                              *
* - Add OKCODE (type OK) in the element list                          *
* - Modify the flow logic of dynpro 0100 :                            *
*   * PROCESS BEFORE OUTPUT.                                          *
*       MODULE pbo_0100.                                              *
*   * PROCESS AFTER INPUT.                                            *
*       MODULE user_command_0100.                                     *
* - Create a status named 'MAIN'                                      *
*   with the buttons : SAVE BACK and EXIT                             *
*---------------------------------------------------------------------*
* The Dynpro 0100 can be uploaded                                     *
* (SE51/Change/utilities/More utilities/Upload-Download/Upload)       *
* at this URL : Z_ALV_MODIFY_PID_DYN_0100.html                        *
*---------------------------------------------------------------------*
* Author : Michel PIOUD - Updated 23-Nov-07                           *
* HomePage : http://www.oocities.org/mpioud                          *
***********************************************************************
CONSTANTS :
  c_x(1) VALUE 'X',
  c_save TYPE syucomm VALUE '&DATASAVE'.
*---------------------------------------------------------------------*
TYPES :
  BEGIN OF ty_s_user,
    bname     TYPE usr04-bname,        " User name
    parid     TYPE usr05-parid,        " Set/Get parameter ID
    parva     TYPE usr05-parva,        " Parameter value
    partext   TYPE tparat-partext,     " Memory ID Text
    name_last TYPE addr3_val-name_last," Last name
  END OF ty_s_user.
*---------------------------------------------------------------------*
CLASS lcl_event_alv DEFINITION DEFERRED.
*---------------------------------------------------------------------*
DATA :
  g_bname TYPE usr05-bname,
  g_parid TYPE usr05-parid,
  go_container TYPE REF TO cl_gui_docking_container,
  go_alv_grid  TYPE REF TO cl_gui_alv_grid,
  go_event_alv TYPE REF TO lcl_event_alv,

  okcode      TYPE syucomm,
  gv_okcode   TYPE syucomm,
  gs_user     TYPE ty_s_user,
  gt_user     TYPE TABLE OF ty_s_user,
  gt_user_old TYPE SORTED TABLE OF ty_s_user
              WITH UNIQUE KEY bname parid.

*---------------------------------------------------------------------*
SELECTION-SCREEN :
  SKIP, BEGIN OF LINE, COMMENT 10(20) v_1 FOR FIELD s_bname."#EC NEEDED
SELECT-OPTIONS s_bname FOR g_bname.
SELECTION-SCREEN END OF LINE.

SELECTION-SCREEN :
  BEGIN OF LINE, COMMENT 10(20) v_2 FOR FIELD s_parid.      "#EC NEEDED
SELECT-OPTIONS s_parid FOR g_parid.
SELECTION-SCREEN END OF LINE.

SELECTION-SCREEN :
  SKIP, BEGIN OF LINE,COMMENT 10(20) v_3 FOR FIELD p_dsplay."#EC NEEDED
PARAMETERS p_dsplay AS CHECKBOX.
SELECTION-SCREEN END OF LINE.

*---------------------------------------------------------------------*
*       CLASS lcl_event_alv DEFINITION
*---------------------------------------------------------------------*
CLASS lcl_event_alv DEFINITION.

  PUBLIC SECTION.
    METHODS:
      h_double_click FOR EVENT double_click OF cl_gui_alv_grid
                     IMPORTING e_row
                               e_column.

ENDCLASS.                              " LCL_EVENT_ALV DEFINITION
*---------------------------------------------------------------------*
*        Class (Implementation)  lcl_event_alv
*---------------------------------------------------------------------*
CLASS lcl_event_alv IMPLEMENTATION.

  METHOD h_double_click.
    READ TABLE gt_user INDEX e_row-index INTO gs_user.
    IF sy-subrc EQ 0.
      PERFORM f_user_command USING '&IC1'.
    ENDIF.
  ENDMETHOD.                           " H_double_click

ENDCLASS.                              " LCL_EVENT_ALV
*---------------------------------------------------------------------*
INITIALIZATION.

  v_1 = 'User'.
  v_2 = 'Parameter Id'.
  v_3 = 'Display only'.

*---------------------------------------------------------------------*
START-OF-SELECTION.

  PERFORM f_read_data.

  CALL SCREEN 100.

*---------------------------------------------------------------------*
*       Module  pbo_0100  OUTPUT
*---------------------------------------------------------------------*
MODULE pbo_0100 OUTPUT.

  IF p_dsplay = c_x.
    SET PF-STATUS 'MAIN' EXCLUDING 'SAVE'.
  ELSE.
    SET PF-STATUS 'MAIN'.
  ENDIF.

  IF go_container IS INITIAL.
    PERFORM create_and_init_alv.
  ENDIF.

ENDMODULE.                             " PBO_0100  OUTPUT
*---------------------------------------------------------------------*
*       Module  user_command_0100  INPUT
*---------------------------------------------------------------------*
MODULE user_command_0100 INPUT.

  gv_okcode = okcode.
  CLEAR okcode.

  CASE gv_okcode.
    WHEN 'BACK'.
      SET SCREEN 0.
    WHEN 'SAVE'.
      PERFORM f_user_command USING c_save.
    WHEN 'EXIT'.
      LEAVE PROGRAM.
  ENDCASE.

ENDMODULE.                             " USER_COMMAND_0100  INPUT
*---------------------------------------------------------------------*
*      Form  f_read_data
*---------------------------------------------------------------------*
FORM f_read_data.

  TYPES :
    BEGIN OF ty_name,
      bname      TYPE usr21-bname,
      name_first TYPE adrp-name_first,
      name_last  TYPE adrp-name_last,
    END OF ty_name,

    BEGIN OF ty_tparat,
      paramid    TYPE tparat-paramid,
      partext    TYPE tparat-partext,
    END OF ty_tparat.

  DATA :
    ls_name TYPE ty_name,
    lt_name TYPE HASHED TABLE OF ty_name
            WITH UNIQUE KEY bname,

    ls_tparat TYPE ty_tparat,
    lt_tparat TYPE SORTED TABLE OF ty_tparat
              WITH UNIQUE KEY paramid,

    lt_user TYPE TABLE OF ty_s_user.

  FIELD-SYMBOLS <user> TYPE ty_s_user.

* Read data
  SELECT u~bname parid parva
    INTO TABLE gt_user
    FROM usr05 AS u
    JOIN usr01 AS s
      ON u~bname = s~bname
   WHERE u~bname IN s_bname
     AND parid IN s_parid.

  IF gt_user[] IS NOT INITIAL.
    lt_user[] = gt_user[].
    SORT lt_user BY bname.
    DELETE ADJACENT DUPLICATES FROM lt_user COMPARING bname.
*   Read user name
    SELECT bname name_first name_last
      INTO TABLE lt_name
      FROM usr21 AS u
      JOIN adrp AS a
        ON u~persnumber = a~persnumber
       FOR ALL ENTRIES IN lt_user
     WHERE bname = lt_user-bname.

    lt_user[] = gt_user[].
    SORT lt_user BY parid.
    DELETE ADJACENT DUPLICATES FROM lt_user COMPARING parid.
*   Memory ID Texts
    SELECT paramid partext
      INTO TABLE lt_tparat
      FROM tparat
       FOR ALL ENTRIES IN lt_user
     WHERE paramid = lt_user-parid
       AND sprache = sy-langu.
  ENDIF.

  LOOP AT gt_user ASSIGNING <user>.

*   Get the parameter-id texts.
    READ TABLE lt_tparat WITH KEY paramid = <user>-parid
                             INTO ls_tparat.
    IF sy-subrc IS INITIAL.
      <user>-partext = ls_tparat-partext.
    ELSEIF sy-langu <> 'E'.
*     Not found, try in English
      SELECT SINGLE partext INTO <user>-partext
                            FROM tparat
                           WHERE paramid = <user>-parid
                             AND sprache = 'E'.
      IF sy-subrc IS INITIAL.
        CLEAR ls_tparat.
        ls_tparat-paramid = <user>-parid.
        ls_tparat-partext = <user>-partext.
        INSERT ls_tparat INTO TABLE lt_tparat.
      ELSEIF sy-langu <> 'D'.
*       Not found, try in German
        SELECT SINGLE partext INTO <user>-partext
                              FROM tparat
                             WHERE paramid = <user>-parid
                               AND sprache = 'D'.
        IF sy-subrc IS INITIAL.
          CLEAR ls_tparat.
          ls_tparat-paramid = <user>-parid.
          ls_tparat-partext = <user>-partext.
          INSERT ls_tparat INTO TABLE lt_tparat.
        ENDIF.
      ENDIF.
    ENDIF.

*   Get user name
    READ TABLE lt_name WITH KEY bname = <user>-bname
                           INTO ls_name.
    IF sy-subrc IS INITIAL.
      CONCATENATE ls_name-name_last ls_name-name_first
             INTO <user>-name_last SEPARATED BY space.
    ELSE.
      <user>-name_last = <user>-bname.
    ENDIF.

  ENDLOOP.

* Save data
  gt_user_old[] = gt_user[].

ENDFORM.                               " F_READ_DATA
*---------------------------------------------------------------------*
*       Form  create_and_init_alv
*---------------------------------------------------------------------*
FORM create_and_init_alv.

* Macro definition
  DEFINE m_fieldcat.
    add 1 to ls_alv_cat-col_pos.
    ls_alv_cat-fieldname = &1.
    ls_alv_cat-ref_table = &2.
    ls_alv_cat-edit      = &3.
    append ls_alv_cat to lt_alv_cat.
  END-OF-DEFINITION.

  DEFINE m_sort.
    add 1 to ls_sort-spos.
    ls_sort-fieldname = &1.
    ls_sort-up        = c_x.
    ls_sort-group     = &2.
    append ls_sort to lt_sort.
  END-OF-DEFINITION.

  DATA:
    ls_variant      TYPE disvariant,
    lt_sort         TYPE lvc_t_sort,
    ls_sort         TYPE lvc_s_sort,
    lt_alv_cat      TYPE lvc_t_fcat,
    ls_alv_cat      TYPE lvc_s_fcat,
    ls_alv_lay      TYPE lvc_s_layo,
    ls_print        TYPE lvc_s_prnt,
    l_offline       TYPE char1,
    lt_toolbar_excl TYPE ui_functions.

  CALL METHOD cl_gui_alv_grid=>offline
    RECEIVING
      e_offline = l_offline.

  IF l_offline EQ 0.
    CREATE OBJECT go_container
      EXPORTING
        extension                   = 2000
      EXCEPTIONS
        cntl_error                  = 1
        cntl_system_error           = 2
        create_error                = 3
        lifetime_error              = 4
        lifetime_dynpro_dynpro_link = 5
        OTHERS                      = 6.
    IF sy-subrc NE 0.
      MESSAGE e208(00) WITH 'The control could not be created'.
    ENDIF.
  ENDIF.

* Create an instance of alv control
  CREATE OBJECT go_alv_grid
    EXPORTING
      i_parent = go_container.

* Build field catalog and sort table
  m_fieldcat 'BNAME'     'USR05'     ''.
  m_fieldcat 'NAME_LAST' 'ADDR3_VAL' ''.
  m_fieldcat 'PARID'     'USR05'     ''.
  m_fieldcat 'PARTEXT'   'TPARAT'    ''.
  IF p_dsplay IS INITIAL.
    m_fieldcat 'PARVA'   'USR05'     c_x.  " Column alterable
  ELSE.
    m_fieldcat 'PARVA'   'USR05'     ''.
  ENDIF.

  m_sort 'BNAME'     'UL'.             " Line break
  m_sort 'NAME_LAST' ''.
  m_sort 'PARID'     ''.

* Layout
  CLEAR ls_alv_lay.
  ls_alv_lay-zebra      = c_x.
  ls_alv_lay-cwidth_opt = c_x.

  IF l_offline EQ 0.
*   Exclude toolbar functions
    APPEND cl_gui_alv_grid=>mc_fc_detail         TO lt_toolbar_excl.
    APPEND cl_gui_alv_grid=>mc_fc_info           TO lt_toolbar_excl.
    APPEND cl_gui_alv_grid=>mc_fc_graph          TO lt_toolbar_excl.
    APPEND cl_gui_alv_grid=>mc_fc_view_crystal   TO lt_toolbar_excl.
    APPEND cl_gui_alv_grid=>mc_fc_loc_delete_row TO lt_toolbar_excl.
    APPEND cl_gui_alv_grid=>mc_fc_loc_append_row TO lt_toolbar_excl.
    APPEND cl_gui_alv_grid=>mc_fc_loc_insert_row TO lt_toolbar_excl.
    APPEND cl_gui_alv_grid=>mc_fc_loc_copy_row   TO lt_toolbar_excl.
    APPEND cl_gui_alv_grid=>mc_fc_loc_undo       TO lt_toolbar_excl.
    APPEND cl_gui_alv_grid=>mc_fc_check          TO lt_toolbar_excl.
    APPEND cl_gui_alv_grid=>mc_fc_refresh        TO lt_toolbar_excl.

    CREATE OBJECT go_event_alv.

    SET HANDLER go_event_alv->h_double_click
            FOR go_alv_grid.

  ENDIF.

  ls_variant-report = sy-cprog.

* Display
  CALL METHOD go_alv_grid->set_table_for_first_display
    EXPORTING
      is_variant           = ls_variant
      is_layout            = ls_alv_lay
      is_print             = ls_print
      i_save               = 'A'
      it_toolbar_excluding = lt_toolbar_excl
    CHANGING
      it_sort              = lt_sort
      it_outtab            = gt_user[]
      it_fieldcatalog      = lt_alv_cat.

ENDFORM.                               " CREATE_AND_INIT_ALV
*---------------------------------------------------------------------*
*       FORM F_USER_COMMAND                                           *
*---------------------------------------------------------------------*
FORM f_user_command USING u_ucomm TYPE sy-ucomm.

* Macro definition
  DEFINE m_bdc_dynpro.
    clear ls_bdcdata.
    ls_bdcdata-program  = &1.
    ls_bdcdata-dynpro   = &2.
    ls_bdcdata-dynbegin = c_x.
    ls_bdcdata-fnam     = 'BDC_OKCODE'.
    ls_bdcdata-fval     = &3.
    append ls_bdcdata to lt_bdcdata.
  END-OF-DEFINITION.

  DEFINE m_bdc_field.
    clear ls_bdcdata.
    ls_bdcdata-fnam = &1.
    ls_bdcdata-fval = &2.
    append ls_bdcdata to lt_bdcdata.
  END-OF-DEFINITION.

  DATA :
    l_valid    TYPE flag,
    ls_userold TYPE ty_s_user,
    ls_message TYPE bdcmsgcoll,
    lt_message TYPE TABLE OF bdcmsgcoll,
    ls_bdcdata TYPE bdcdata,
    lt_bdcdata TYPE TABLE OF bdcdata.

  CASE u_ucomm.
    WHEN '&IC1'.
      m_bdc_dynpro 'SAPLSUU5' '0050' '=SHOW'.
      m_bdc_field  'USR02-BNAME' gs_user-bname.

*     Tabstrip Parameter-Id
      m_bdc_dynpro 'SAPLSUU5' '0100' '=PARAM'.

*     Show user
      CALL TRANSACTION 'SU01' USING lt_bdcdata MODE 'E'
                      MESSAGES INTO lt_message.
      READ TABLE lt_message WITH KEY msgid = '01'
                                     msgnr = '495'
                        TRANSPORTING NO FIELDS.
      CHECK sy-subrc EQ 0.
*     You are not authorized to display users
      MESSAGE i495(01).
    WHEN c_save.
*     Verification of Changes
      CALL METHOD go_alv_grid->check_changed_data
        IMPORTING
          e_valid = l_valid.

      CHECK NOT l_valid IS INITIAL.

*     Update User's Parameter-IDs
      LOOP AT gt_user INTO gs_user.
        READ TABLE gt_user_old INTO ls_userold
          WITH KEY bname = gs_user-bname
                   parid = gs_user-parid.

        CHECK gs_user-parva <> ls_userold-parva.
        m_bdc_dynpro 'SAPLSUU5' '0050' '=CHAN'.
        m_bdc_field  'USR02-BNAME' gs_user-bname.

*       Tabstrip Parameter-Id
        m_bdc_dynpro 'SAPLSUU5' '0100' '=PARAM'.

*       Last page
        m_bdc_dynpro 'SAPLSUU5' '0100' '=P++'.

*       Previous page
        m_bdc_dynpro 'SAPLSUU5' '0100' '=P+'.

        m_bdc_dynpro 'SAPLSUU5' '0100' '=CHECK'.
        m_bdc_field  'USPARAM-PARID(10)' gs_user-parid.
        m_bdc_field  'USPARAM-PARVA(10)' gs_user-parva.

*       Save
        m_bdc_dynpro 'SAPLSUU5' '0100' '=UPD'.

        CALL TRANSACTION 'SU01' USING lt_bdcdata MODE 'E'
                        MESSAGES INTO lt_message.
        READ TABLE lt_message WITH KEY msgid = '01'
                                       msgnr = '492'
                                  INTO ls_message.
        IF sy-subrc EQ 0.
*         You are not authorized to change users in group &
          MESSAGE i492(01) WITH ls_message-msgv1.
          EXIT.
        ENDIF.
        REFRESH lt_bdcdata.
      ENDLOOP.

      gt_user_old[] = gt_user[].

  ENDCASE.

ENDFORM.                               " F_USER_COMMAND
************* END OF PROGRAM Z_ALV_MODIFY_PID ***********************