"! Version constants for abap-log
CLASS zcl_alog_version DEFINITION
  PUBLIC
  FINAL
  CREATE PRIVATE.

  PUBLIC SECTION.
    CONSTANTS:
      "! Version of abap-log library in major.minor.revision format
      gc_version TYPE string VALUE '0.2.0'.
    CLASS-METHODS:
      class_constructor,
      "! Factory method
      "! @parameter iv_version | Version string
      "! @parameter ro_version | Created instance
      "! @raising zcx_alog_illegal_argument | iv_version does not have the required format
      of IMPORTING iv_version        TYPE string
         RETURNING VALUE(ro_version) TYPE REF TO zcl_alog_version
         RAISING   zcx_alog_illegal_argument,
      "! Compare two version instances
      "! @parameter io_version_a | Version A
      "! @parameter io_version_b | Version B
      "! @parameter rv_result |

      "!
Less than 0 = version A is lower than version B

      "!
Greater than 0 = version A is higher than version B

      "!
Equal to 0 = versions are identical

      "!

      "! @raising zcx_alog_argument_null | io_version_a and io_version_b cannot be null
      compare IMPORTING io_version_a     TYPE REF TO zcl_alog_version
                        io_version_b     TYPE REF TO zcl_alog_version
              RETURNING VALUE(rv_result) TYPE i
              RAISING   zcx_alog_argument_null.
    METHODS:
      "! Compare this version to another one
      "! @parameter io_version | The version to compare this instance to
      "! @parameter rv_result | See compare
      "! @raising zcx_alog_argument_null | io_version cannot be null
      compare_to IMPORTING io_version       TYPE REF TO zcl_alog_version
                 RETURNING VALUE(rv_result) TYPE i
                 RAISING   zcx_alog_argument_null.
    CLASS-DATA:
      " These are for the currently installed version
      gv_major       TYPE i READ-ONLY,
      gv_minor       TYPE i READ-ONLY,
      gv_revision    TYPE i READ-ONLY,
      gv_is_snapshot TYPE abap_bool READ-ONLY,
      go_current     TYPE REF TO zcl_alog_version READ-ONLY.
    DATA:
      mv_version     TYPE string READ-ONLY,
      mv_major       TYPE i READ-ONLY,
      mv_minor       TYPE i READ-ONLY,
      mv_revision    TYPE i READ-ONLY,
      mv_is_snapshot TYPE abap_bool READ-ONLY.
  PROTECTED SECTION.
  PRIVATE SECTION.
    METHODS:
      constructor IMPORTING iv_version TYPE string.
ENDCLASS.

CLASS zcl_alog_version IMPLEMENTATION.
  METHOD class_constructor.
    go_current = NEW #( gc_version ).
    gv_major = go_current->mv_major.
    gv_minor = go_current->mv_minor.
    gv_revision = go_current->mv_revision.
    gv_is_snapshot = go_current->mv_is_snapshot.
  ENDMETHOD.

  METHOD constructor.
    mv_version = iv_version.

    SPLIT mv_version AT '-' INTO TABLE DATA(lt_split1).

    IF lines( lt_split1 ) = 2.
      mv_is_snapshot = abap_true.
    ENDIF.

    SPLIT lt_split1[ 1 ] AT '.' INTO TABLE DATA(lt_split2).

    mv_major = lt_split2[ 1 ].
    mv_minor = lt_split2[ 2 ].
    mv_revision = lt_split2[ 3 ].
  ENDMETHOD.

  METHOD compare.
    DEFINE compare_attr.
      rv_result = io_version_a->&1 - io_version_b->&1.
    END-OF-DEFINITION.

    IF io_version_a IS NOT BOUND OR io_version_b IS NOT BOUND.
      RAISE EXCEPTION TYPE zcx_alog_argument_null
        EXPORTING
          iv_variable_name = 'IO_VERSION_A / IO_VERSION_B'.
    ENDIF.

    WHILE rv_result = 0.
      CASE sy-index.
        WHEN 1.
          compare_attr mv_major.
        WHEN 2.
          compare_attr mv_minor.
        WHEN 3.
          compare_attr mv_revision.
        WHEN 4.
          rv_result = COND #( WHEN io_version_a->mv_is_snapshot = io_version_b->mv_is_snapshot
                              THEN 0
                              WHEN io_version_a->mv_is_snapshot = abap_true THEN -1
                              WHEN io_version_b->mv_is_snapshot = abap_true THEN 1 ).
        WHEN OTHERS.
          EXIT.
      ENDCASE.
    ENDWHILE.
  ENDMETHOD.

  METHOD compare_to.
    rv_result = compare( io_version_a = me io_version_b = io_version ).
  ENDMETHOD.

  METHOD of.
    IF NOT matches( val = iv_version regex = `\d+\.\d+\.\d+(-.+)?` ).
      RAISE EXCEPTION TYPE zcx_alog_illegal_argument
        EXPORTING
          iv_reason = 'Version format invalid'
          iv_value  = iv_version ##NO_TEXT.
    ENDIF.

    ro_version = NEW #( iv_version ).
  ENDMETHOD.
ENDCLASS.

"! Version constants for abap-log
CLASS zcl_alog_version DEFINITION
  PUBLIC
  FINAL
  CREATE PRIVATE.

  PUBLIC SECTION.
    CONSTANTS:
      "! Version of abap-log library in major.minor.revision format
      gc_version TYPE string VALUE '0.2.1-SNAPSHOT'.
    CLASS-METHODS:
      class_constructor,
      "! Factory method
      "! @parameter iv_version | Version string
      "! @parameter ro_version | Created instance
      "! @raising zcx_alog_illegal_argument | iv_version does not have the required format
      of IMPORTING iv_version        TYPE string
         RETURNING VALUE(ro_version) TYPE REF TO zcl_alog_version
         RAISING   zcx_alog_illegal_argument,
      "! Compare two version instances
      "! @parameter io_version_a | Version A
      "! @parameter io_version_b | Version B
      "! @parameter rv_result |

      "!
Less than 0 = version A is lower than version B

      "!
Greater than 0 = version A is higher than version B

      "!
Equal to 0 = versions are identical

      "!

      "! @raising zcx_alog_argument_null | io_version_a and io_version_b cannot be null
      compare IMPORTING io_version_a     TYPE REF TO zcl_alog_version
                        io_version_b     TYPE REF TO zcl_alog_version
              RETURNING VALUE(rv_result) TYPE i
              RAISING   zcx_alog_argument_null.
    METHODS:
      "! Compare this version to another one
      "! @parameter io_version | The version to compare this instance to
      "! @parameter rv_result | See compare
      "! @raising zcx_alog_argument_null | io_version cannot be null
      compare_to IMPORTING io_version       TYPE REF TO zcl_alog_version
                 RETURNING VALUE(rv_result) TYPE i
                 RAISING   zcx_alog_argument_null.
    CLASS-DATA:
      " These are for the currently installed version
      gv_major       TYPE i READ-ONLY,
      gv_minor       TYPE i READ-ONLY,
      gv_revision    TYPE i READ-ONLY,
      gv_is_snapshot TYPE abap_bool READ-ONLY,
      go_current     TYPE REF TO zcl_alog_version READ-ONLY.
    DATA:
      mv_version     TYPE string READ-ONLY,
      mv_major       TYPE i READ-ONLY,
      mv_minor       TYPE i READ-ONLY,
      mv_revision    TYPE i READ-ONLY,
      mv_is_snapshot TYPE abap_bool READ-ONLY.
  PROTECTED SECTION.
  PRIVATE SECTION.
    METHODS:
      constructor IMPORTING iv_version TYPE string.
ENDCLASS.

CLASS zcl_alog_version IMPLEMENTATION.
  METHOD class_constructor.
    go_current = NEW #( gc_version ).
    gv_major = go_current->mv_major.
    gv_minor = go_current->mv_minor.
    gv_revision = go_current->mv_revision.
    gv_is_snapshot = go_current->mv_is_snapshot.
  ENDMETHOD.

  METHOD constructor.
    mv_version = iv_version.

    SPLIT mv_version AT '-' INTO TABLE DATA(lt_split1).

    IF lines( lt_split1 ) = 2.
      mv_is_snapshot = abap_true.
    ENDIF.

    SPLIT lt_split1[ 1 ] AT '.' INTO TABLE DATA(lt_split2).

    mv_major = lt_split2[ 1 ].
    mv_minor = lt_split2[ 2 ].
    mv_revision = lt_split2[ 3 ].
  ENDMETHOD.

  METHOD compare.
    DEFINE compare_attr.
      rv_result = io_version_a->&1 - io_version_b->&1.
    END-OF-DEFINITION.

    IF io_version_a IS NOT BOUND OR io_version_b IS NOT BOUND.
      RAISE EXCEPTION TYPE zcx_alog_argument_null
        EXPORTING
          iv_variable_name = 'IO_VERSION_A / IO_VERSION_B'.
    ENDIF.

    WHILE rv_result = 0.
      CASE sy-index.
        WHEN 1.
          compare_attr mv_major.
        WHEN 2.
          compare_attr mv_minor.
        WHEN 3.
          compare_attr mv_revision.
        WHEN 4.
          rv_result = COND #( WHEN io_version_a->mv_is_snapshot = io_version_b->mv_is_snapshot
                              THEN 0
                              WHEN io_version_a->mv_is_snapshot = abap_true THEN -1
                              WHEN io_version_b->mv_is_snapshot = abap_true THEN 1 ).
        WHEN OTHERS.
          EXIT.
      ENDCASE.
    ENDWHILE.
  ENDMETHOD.

  METHOD compare_to.
    rv_result = compare( io_version_a = me io_version_b = io_version ).
  ENDMETHOD.

  METHOD of.
    IF NOT matches( val = iv_version regex = `\d+\.\d+\.\d+(-.+)?` ).
      RAISE EXCEPTION TYPE zcx_alog_illegal_argument
        EXPORTING
          iv_reason = 'Version format invalid'
          iv_value  = iv_version ##NO_TEXT.
    ENDIF.

    ro_version = NEW #( iv_version ).
  ENDMETHOD.
ENDCLASS.

Prepare next development version

Prepare next development version


CLASS zcl_abapgit_html_action_utils DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    CLASS-METHODS parse_post_form_data
      IMPORTING
        !it_post_data TYPE cnht_post_data_tab
        !iv_upper_cased TYPE abap_bool DEFAULT abap_false
      RETURNING
        VALUE(rt_fields) TYPE tihttpnvp .
    CLASS-METHODS parse_fields
      IMPORTING
        !iv_string       TYPE clike
        !iv_upper_cased  TYPE abap_bool DEFAULT abap_false
      RETURNING
        VALUE(rt_fields) TYPE tihttpnvp .
    CLASS-METHODS parse_fields_upper_case_name
      IMPORTING
        !iv_string       TYPE clike
      RETURNING
        VALUE(rt_fields) TYPE tihttpnvp .
    CLASS-METHODS translate_postdata
      IMPORTING
        !it_postdata TYPE cnht_post_data_tab
      RETURNING
        VALUE(rv_string) TYPE string .

    CLASS-METHODS get_field
      IMPORTING
        !iv_name   TYPE string
        !it_field  TYPE tihttpnvp
        !iv_decode TYPE abap_bool DEFAULT abap_false
      CHANGING
        !cg_field  TYPE any .
    CLASS-METHODS jump_encode
      IMPORTING
        !iv_obj_type     TYPE tadir-object
        !iv_obj_name     TYPE tadir-obj_name
      RETURNING
        VALUE(rv_string) TYPE string .
    CLASS-METHODS dir_encode
      IMPORTING
        !iv_path         TYPE string
      RETURNING
        VALUE(rv_string) TYPE string .

    CLASS-METHODS file_encode
      IMPORTING
        !iv_key          TYPE zif_abapgit_persistence=>ty_repo-key
        !ig_file         TYPE any
      RETURNING
        VALUE(rv_string) TYPE string .
    CLASS-METHODS obj_encode
      IMPORTING
        !iv_key          TYPE zif_abapgit_persistence=>ty_repo-key
        !ig_object       TYPE any
      RETURNING
        VALUE(rv_string) TYPE string .

    CLASS-METHODS dbkey_encode
      IMPORTING
        !is_key          TYPE zif_abapgit_persistence=>ty_content
      RETURNING
        VALUE(rv_string) TYPE string .

  PROTECTED SECTION.
  PRIVATE SECTION.

    CLASS-METHODS field_keys_to_upper
      CHANGING
        !ct_fields TYPE tihttpnvp .
    CLASS-METHODS add_field
      IMPORTING
        !iv_name  TYPE string
        !ig_field TYPE any
      CHANGING
        !ct_field TYPE tihttpnvp .
    CLASS-METHODS unescape
      IMPORTING
        !iv_string       TYPE string
      RETURNING
        VALUE(rv_string) TYPE string .
ENDCLASS.

CLASS ZCL_ABAPGIT_HTML_ACTION_UTILS IMPLEMENTATION.

  METHOD add_field.

    DATA ls_field LIKE LINE OF ct_field.

    FIELD-SYMBOLS <lg_src> TYPE any.

    ls_field-name = iv_name.

    CASE cl_abap_typedescr=>describe_by_data( ig_field )->kind.
      WHEN cl_abap_typedescr=>kind_elem.
        ls_field-value = ig_field.
      WHEN cl_abap_typedescr=>kind_struct.
        ASSIGN COMPONENT iv_name OF STRUCTURE ig_field TO <lg_src>.
        ASSERT <lg_src> IS ASSIGNED.
        ls_field-value = <lg_src>.
      WHEN OTHERS.
        ASSERT 0 = 1.
    ENDCASE.

    APPEND ls_field TO ct_field.

  ENDMETHOD.

  METHOD dbkey_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING iv_name = 'TYPE'
                         ig_field = is_key-type CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'VALUE'
                         ig_field = is_key-value CHANGING ct_field = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.

  METHOD dir_encode.

    DATA: lt_fields TYPE tihttpnvp.
    add_field( EXPORTING iv_name = 'PATH'
                         ig_field = iv_path CHANGING ct_field = lt_fields ).
    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.

  METHOD field_keys_to_upper.

    FIELD-SYMBOLS <ls_field> LIKE LINE OF ct_fields.

    LOOP AT ct_fields ASSIGNING <ls_field>.
      <ls_field>-name = to_upper( <ls_field>-name ).
    ENDLOOP.

  ENDMETHOD.

  METHOD file_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING iv_name = 'KEY'
                         ig_field = iv_key CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'PATH'
                         ig_field = ig_file CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'FILENAME'
                         ig_field = ig_file CHANGING ct_field = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.

  METHOD get_field.

    DATA: lv_value TYPE string.

    FIELD-SYMBOLS: <ls_field> LIKE LINE OF it_field,
                   <lg_dest>  TYPE any.

    READ TABLE it_field ASSIGNING <ls_field> WITH KEY name = iv_name.
    IF sy-subrc IS NOT INITIAL.
      RETURN.
    ENDIF.

    lv_value = <ls_field>-value.

    IF iv_decode = abap_true.
      lv_value = cl_http_utility=>unescape_url( escaped = lv_value ).
    ENDIF.

    CASE cl_abap_typedescr=>describe_by_data( cg_field )->kind.
      WHEN cl_abap_typedescr=>kind_elem.
        cg_field = lv_value.
      WHEN cl_abap_typedescr=>kind_struct.
        ASSIGN COMPONENT iv_name OF STRUCTURE cg_field TO <lg_dest>.
        ASSERT <lg_dest> IS ASSIGNED.
        <lg_dest> = lv_value.
      WHEN OTHERS.
        ASSERT 0 = 1.
    ENDCASE.

  ENDMETHOD.

  METHOD jump_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING iv_name = 'TYPE'
                         ig_field = iv_obj_type CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'NAME'
                         ig_field = iv_obj_name CHANGING ct_field = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.

  METHOD obj_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING iv_name = 'KEY'
                         ig_field = iv_key CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'OBJ_TYPE'
                         ig_field = ig_object CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'OBJ_NAME'
                         ig_field = ig_object CHANGING ct_field = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.

  METHOD parse_fields.

    DATA:
      lt_substrings TYPE string_table,
      ls_field      LIKE LINE OF rt_fields.

    FIELD-SYMBOLS <lv_substring> LIKE LINE OF lt_substrings.

    SPLIT iv_string AT '&' INTO TABLE lt_substrings.

    LOOP AT lt_substrings ASSIGNING <lv_substring>.

      CLEAR ls_field.
      <lv_substring> = unescape( <lv_substring> ).
      " On attempt to change unescaping -> run unit tests to check !

      ls_field-name = substring_before(
        val = <lv_substring>
        sub = '=' ).

      ls_field-value = substring_after(
        val = <lv_substring>
        sub = '=' ).

      IF ls_field IS INITIAL. " Not a field with proper structure
        CONTINUE.
      ENDIF.

      APPEND ls_field TO rt_fields.

    ENDLOOP.

    IF iv_upper_cased = abap_true.
      field_keys_to_upper( CHANGING ct_fields = rt_fields ).
    ENDIF.

  ENDMETHOD.

  METHOD parse_fields_upper_case_name.

    rt_fields = parse_fields(
      iv_string      = iv_string
      iv_upper_cased = abap_true ).

  ENDMETHOD.

  METHOD parse_post_form_data.

    DATA lv_serialized_post_data TYPE string.

    lv_serialized_post_data = translate_postdata( it_post_data ).
    IF iv_upper_cased = abap_true.
      rt_fields = parse_fields_upper_case_name( lv_serialized_post_data ).
    ELSE.
      rt_fields = parse_fields( lv_serialized_post_data ).
    ENDIF.

  ENDMETHOD.

  METHOD translate_postdata.

    DATA: lt_post_data       TYPE cnht_post_data_tab,
          ls_last_line       TYPE cnht_post_data_line,
          lv_last_line_index TYPE i.

    IF it_postdata IS INITIAL.
      RETURN. "Nothing to do
    ENDIF.

    lt_post_data = it_postdata.

    "Save the last line for separate merge, because we don't need its trailing spaces
    WHILE ls_last_line IS INITIAL.
      lv_last_line_index = lines( lt_post_data ).
      READ TABLE lt_post_data INTO ls_last_line INDEX lv_last_line_index.
      DELETE lt_post_data INDEX lv_last_line_index.
    ENDWHILE.

    CONCATENATE LINES OF lt_post_data INTO rv_string
      IN CHARACTER MODE RESPECTING BLANKS.
    CONCATENATE rv_string ls_last_line INTO rv_string
      IN CHARACTER MODE.

  ENDMETHOD.

  METHOD unescape.
* do not use cl_http_utility as it does strange things with the encoding
    rv_string = iv_string.

* todo, more to be added here
    REPLACE ALL OCCURRENCES OF '%3F' IN rv_string WITH '?'.
    REPLACE ALL OCCURRENCES OF '%3D' IN rv_string WITH '='.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_html_action_utils DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    CLASS-METHODS parse_post_form_data
      IMPORTING
        !it_post_data TYPE cnht_post_data_tab
        !iv_upper_cased TYPE abap_bool DEFAULT abap_false
      RETURNING
        VALUE(rt_fields) TYPE tihttpnvp .
    CLASS-METHODS parse_fields
      IMPORTING
        !iv_string       TYPE clike
        !iv_upper_cased  TYPE abap_bool DEFAULT abap_false
      RETURNING
        VALUE(rt_fields) TYPE tihttpnvp .
    CLASS-METHODS parse_fields_upper_case_name
      IMPORTING
        !iv_string       TYPE clike
      RETURNING
        VALUE(rt_fields) TYPE tihttpnvp .
    CLASS-METHODS translate_postdata
      IMPORTING
        !it_postdata TYPE cnht_post_data_tab
      RETURNING
        VALUE(rv_string) TYPE string .

    CLASS-METHODS get_field
      IMPORTING
        !iv_name   TYPE string
        !it_field  TYPE tihttpnvp
        !iv_decode TYPE abap_bool DEFAULT abap_false
      CHANGING
        !cg_field  TYPE any .
    CLASS-METHODS jump_encode
      IMPORTING
        !iv_obj_type     TYPE tadir-object
        !iv_obj_name     TYPE tadir-obj_name
      RETURNING
        VALUE(rv_string) TYPE string .
    CLASS-METHODS dir_encode
      IMPORTING
        !iv_path         TYPE string
      RETURNING
        VALUE(rv_string) TYPE string .

    CLASS-METHODS file_encode
      IMPORTING
        !iv_key          TYPE zif_abapgit_persistence=>ty_repo-key
        !ig_file         TYPE any
      RETURNING
        VALUE(rv_string) TYPE string .
    CLASS-METHODS obj_encode
      IMPORTING
        !iv_key          TYPE zif_abapgit_persistence=>ty_repo-key
        !ig_object       TYPE any
      RETURNING
        VALUE(rv_string) TYPE string .

    CLASS-METHODS dbkey_encode
      IMPORTING
        !is_key          TYPE zif_abapgit_persistence=>ty_content
      RETURNING
        VALUE(rv_string) TYPE string .

  PROTECTED SECTION.
  PRIVATE SECTION.

    CLASS-METHODS field_keys_to_upper
      CHANGING
        !ct_fields TYPE tihttpnvp .
    CLASS-METHODS add_field
      IMPORTING
        !iv_name  TYPE string
        !ig_field TYPE any
      CHANGING
        !ct_field TYPE tihttpnvp .
    CLASS-METHODS unescape
      IMPORTING
        !iv_string       TYPE string
      RETURNING
        VALUE(rv_string) TYPE string .
ENDCLASS.

CLASS ZCL_ABAPGIT_HTML_ACTION_UTILS IMPLEMENTATION.

  METHOD add_field.

    DATA ls_field LIKE LINE OF ct_field.

    FIELD-SYMBOLS <lg_src> TYPE any.

    ls_field-name = iv_name.

    CASE cl_abap_typedescr=>describe_by_data( ig_field )->kind.
      WHEN cl_abap_typedescr=>kind_elem.
        ls_field-value = ig_field.
      WHEN cl_abap_typedescr=>kind_struct.
        ASSIGN COMPONENT iv_name OF STRUCTURE ig_field TO <lg_src>.
        ASSERT <lg_src> IS ASSIGNED.
        ls_field-value = <lg_src>.
      WHEN OTHERS.
        ASSERT 0 = 1.
    ENDCASE.

    APPEND ls_field TO ct_field.

  ENDMETHOD.

  METHOD dbkey_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING iv_name = 'TYPE'
                         ig_field = is_key-type CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'VALUE'
                         ig_field = is_key-value CHANGING ct_field = lt_fields ).

    rv_string = cl_http_utility=>fields_to_string( lt_fields ).

  ENDMETHOD.

  METHOD dir_encode.

    DATA: lt_fields TYPE tihttpnvp.
    add_field( EXPORTING iv_name = 'PATH'
                         ig_field = iv_path CHANGING ct_field = lt_fields ).
    rv_string = cl_http_utility=>fields_to_string( lt_fields ).

  ENDMETHOD.

  METHOD field_keys_to_upper.

    FIELD-SYMBOLS <ls_field> LIKE LINE OF ct_fields.

    LOOP AT ct_fields ASSIGNING <ls_field>.
      <ls_field>-name = to_upper( <ls_field>-name ).
    ENDLOOP.

  ENDMETHOD.

  METHOD file_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING iv_name = 'KEY'
                         ig_field = iv_key CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'PATH'
                         ig_field = ig_file CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'FILENAME'
                         ig_field = ig_file CHANGING ct_field = lt_fields ).

    rv_string = cl_http_utility=>fields_to_string( lt_fields ).

  ENDMETHOD.

  METHOD get_field.

    DATA: lv_value TYPE string.

    FIELD-SYMBOLS: <ls_field> LIKE LINE OF it_field,
                   <lg_dest>  TYPE any.

    READ TABLE it_field ASSIGNING <ls_field> WITH KEY name = iv_name.
    IF sy-subrc IS NOT INITIAL.
      RETURN.
    ENDIF.

    lv_value = <ls_field>-value.

    IF iv_decode = abap_true.
      lv_value = cl_http_utility=>unescape_url( escaped = lv_value ).
    ENDIF.

    CASE cl_abap_typedescr=>describe_by_data( cg_field )->kind.
      WHEN cl_abap_typedescr=>kind_elem.
        cg_field = lv_value.
      WHEN cl_abap_typedescr=>kind_struct.
        ASSIGN COMPONENT iv_name OF STRUCTURE cg_field TO <lg_dest>.
        ASSERT <lg_dest> IS ASSIGNED.
        <lg_dest> = lv_value.
      WHEN OTHERS.
        ASSERT 0 = 1.
    ENDCASE.

  ENDMETHOD.

  METHOD jump_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING iv_name = 'TYPE'
                         ig_field = iv_obj_type CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'NAME'
                         ig_field = iv_obj_name CHANGING ct_field = lt_fields ).

    rv_string = cl_http_utility=>fields_to_string( lt_fields ).

  ENDMETHOD.

  METHOD obj_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING iv_name = 'KEY'
                         ig_field = iv_key CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'OBJ_TYPE'
                         ig_field = ig_object CHANGING ct_field = lt_fields ).
    add_field( EXPORTING iv_name = 'OBJ_NAME'
                         ig_field = ig_object CHANGING ct_field = lt_fields ).

    rv_string = cl_http_utility=>fields_to_string( lt_fields ).

  ENDMETHOD.

  METHOD parse_fields.

    DATA:
      lt_substrings TYPE string_table,
      ls_field      LIKE LINE OF rt_fields.

    FIELD-SYMBOLS <lv_substring> LIKE LINE OF lt_substrings.

    SPLIT iv_string AT '&' INTO TABLE lt_substrings.

    LOOP AT lt_substrings ASSIGNING <lv_substring>.

      CLEAR ls_field.
      <lv_substring> = unescape( <lv_substring> ).
      " On attempt to change unescaping -> run unit tests to check !

      ls_field-name = substring_before(
        val = <lv_substring>
        sub = '=' ).

      ls_field-value = substring_after(
        val = <lv_substring>
        sub = '=' ).

      IF ls_field IS INITIAL. " Not a field with proper structure
        CONTINUE.
      ENDIF.

      APPEND ls_field TO rt_fields.

    ENDLOOP.

    IF iv_upper_cased = abap_true.
      field_keys_to_upper( CHANGING ct_fields = rt_fields ).
    ENDIF.

  ENDMETHOD.

  METHOD parse_fields_upper_case_name.

    rt_fields = parse_fields(
      iv_string      = iv_string
      iv_upper_cased = abap_true ).

  ENDMETHOD.

  METHOD parse_post_form_data.

    DATA lv_serialized_post_data TYPE string.

    lv_serialized_post_data = translate_postdata( it_post_data ).
    IF iv_upper_cased = abap_true.
      rt_fields = parse_fields_upper_case_name( lv_serialized_post_data ).
    ELSE.
      rt_fields = parse_fields( lv_serialized_post_data ).
    ENDIF.

  ENDMETHOD.

  METHOD translate_postdata.

    DATA: lt_post_data       TYPE cnht_post_data_tab,
          ls_last_line       TYPE cnht_post_data_line,
          lv_last_line_index TYPE i.

    IF it_postdata IS INITIAL.
      RETURN. "Nothing to do
    ENDIF.

    lt_post_data = it_postdata.

    "Save the last line for separate merge, because we don't need its trailing spaces
    WHILE ls_last_line IS INITIAL.
      lv_last_line_index = lines( lt_post_data ).
      READ TABLE lt_post_data INTO ls_last_line INDEX lv_last_line_index.
      DELETE lt_post_data INDEX lv_last_line_index.
    ENDWHILE.

    CONCATENATE LINES OF lt_post_data INTO rv_string
      IN CHARACTER MODE RESPECTING BLANKS.
    CONCATENATE rv_string ls_last_line INTO rv_string
      IN CHARACTER MODE.

  ENDMETHOD.

  METHOD unescape.
* do not use cl_http_utility as it does strange things with the encoding
    rv_string = iv_string.

* todo, more to be added here
    REPLACE ALL OCCURRENCES OF '%3F' IN rv_string WITH '?'.
    REPLACE ALL OCCURRENCES OF '%3D' IN rv_string WITH '='.

  ENDMETHOD.
ENDCLASS.

use non interfaced fields_to_string() (#4378)


REPORT zabapgit LINE-SIZE 100.

* See http://www.abapgit.org

CONSTANTS: gc_xml_version  TYPE string VALUE 'v1.0.0',      "#EC NOTEXT
           gc_abap_version TYPE string VALUE 'v1.17.20'.    "#EC NOTEXT

********************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2014 abapGit Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
********************************************************************************

SELECTION-SCREEN BEGIN OF SCREEN 1001.
* dummy for triggering screen
SELECTION-SCREEN END OF SCREEN 1001.

INCLUDE zabapgit_password_dialog. " !!! Contains SELECTION SCREEN

INCLUDE zabapgit_definitions.
INCLUDE zabapgit_macros.
INCLUDE zabapgit_exceptions.
INCLUDE zabapgit_zlib.
INCLUDE zabapgit_html.
INCLUDE zabapgit_util.
INCLUDE zabapgit_xml.

INCLUDE zabapgit_app. " Some deferred definitions here
INCLUDE zabapgit_persistence_old.
INCLUDE zabapgit_persistence.
INCLUDE zabapgit_dot_abapgit.
INCLUDE zabapgit_sap_package.

INCLUDE zabapgit_stage.
INCLUDE zabapgit_git_helpers.
INCLUDE zabapgit_repo.
INCLUDE zabapgit_stage_logic.
INCLUDE zabapgit_git.
INCLUDE zabapgit_objects.
INCLUDE zabapgit_tadir.
INCLUDE zabapgit_file_status.
INCLUDE zabapgit_popups.
INCLUDE zabapgit_zip.
INCLUDE zabapgit_objects_impl.

INCLUDE zabapgit_object_serializing. " All serializing classes here

INCLUDE zabapgit_repo_impl.
INCLUDE zabapgit_background.
INCLUDE zabapgit_transport.

INCLUDE zabapgit_services. " All services here
INCLUDE zabapgit_gui_pages. " All GUI pages here
INCLUDE zabapgit_gui_pages_userexit IF FOUND.
INCLUDE zabapgit_gui_router.
INCLUDE zabapgit_gui.

INCLUDE zabapgit_app_impl.
INCLUDE zabapgit_unit_test.
INCLUDE zabapgit_forms.

**********************************************************************
INITIALIZATION.
  lcl_password_dialog=>on_screen_init( ).

START-OF-SELECTION.
  PERFORM run.

* Hide Execute button from screen
AT SELECTION-SCREEN OUTPUT.
  IF sy-dynnr = lcl_password_dialog=>dynnr.
    lcl_password_dialog=>on_screen_output( ).
  ELSE.
    PERFORM output.
  ENDIF.

* SAP back command re-direction
AT SELECTION-SCREEN ON EXIT-COMMAND.
  PERFORM exit.

AT SELECTION-SCREEN.
  IF sy-dynnr = lcl_password_dialog=>dynnr.
    lcl_password_dialog=>on_screen_event( sscrfields-ucomm ).
  ENDIF.

REPORT zabapgit LINE-SIZE 100.

* See http://www.abapgit.org

CONSTANTS: gc_xml_version  TYPE string VALUE 'v1.0.0',      "#EC NOTEXT
           gc_abap_version TYPE string VALUE 'v1.18.0'.    "#EC NOTEXT

********************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2014 abapGit Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
********************************************************************************

SELECTION-SCREEN BEGIN OF SCREEN 1001.
* dummy for triggering screen
SELECTION-SCREEN END OF SCREEN 1001.

INCLUDE zabapgit_password_dialog. " !!! Contains SELECTION SCREEN

INCLUDE zabapgit_definitions.
INCLUDE zabapgit_macros.
INCLUDE zabapgit_exceptions.
INCLUDE zabapgit_zlib.
INCLUDE zabapgit_html.
INCLUDE zabapgit_util.
INCLUDE zabapgit_xml.

INCLUDE zabapgit_app. " Some deferred definitions here
INCLUDE zabapgit_persistence_old.
INCLUDE zabapgit_persistence.
INCLUDE zabapgit_dot_abapgit.
INCLUDE zabapgit_sap_package.

INCLUDE zabapgit_stage.
INCLUDE zabapgit_git_helpers.
INCLUDE zabapgit_repo.
INCLUDE zabapgit_stage_logic.
INCLUDE zabapgit_git.
INCLUDE zabapgit_objects.
INCLUDE zabapgit_tadir.
INCLUDE zabapgit_file_status.
INCLUDE zabapgit_popups.
INCLUDE zabapgit_zip.
INCLUDE zabapgit_objects_impl.

INCLUDE zabapgit_object_serializing. " All serializing classes here

INCLUDE zabapgit_repo_impl.
INCLUDE zabapgit_background.
INCLUDE zabapgit_transport.

INCLUDE zabapgit_services. " All services here
INCLUDE zabapgit_gui_pages. " All GUI pages here
INCLUDE zabapgit_gui_pages_userexit IF FOUND.
INCLUDE zabapgit_gui_router.
INCLUDE zabapgit_gui.

INCLUDE zabapgit_app_impl.
INCLUDE zabapgit_unit_test.
INCLUDE zabapgit_forms.

**********************************************************************
INITIALIZATION.
  lcl_password_dialog=>on_screen_init( ).

START-OF-SELECTION.
  PERFORM run.

* Hide Execute button from screen
AT SELECTION-SCREEN OUTPUT.
  IF sy-dynnr = lcl_password_dialog=>dynnr.
    lcl_password_dialog=>on_screen_output( ).
  ELSE.
    PERFORM output.
  ENDIF.

* SAP back command re-direction
AT SELECTION-SCREEN ON EXIT-COMMAND.
  PERFORM exit.

AT SELECTION-SCREEN.
  IF sy-dynnr = lcl_password_dialog=>dynnr.
    lcl_password_dialog=>on_screen_event( sscrfields-ucomm ).
  ENDIF.

bump version to v1.18.0

bump version to v1.18.0


"! Logger base class
"!

"! Inherit from this class and implement entry_internal for the logging logic.
"!

CLASS zcl_alog_logger_base DEFINITION
  PUBLIC
  ABSTRACT
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES:
      zif_alog_logger FINAL METHODS entry,
      zif_alog_attachable.
    ALIASES:
      debug FOR zif_alog_logger~debug,
      entry FOR zif_alog_logger~entry,
      error FOR zif_alog_logger~error,
      exception FOR zif_alog_logger~exception,
      info FOR zif_alog_logger~info,
      warning FOR zif_alog_logger~warning,
      attach FOR zif_alog_attachable~attach,
      detach FOR zif_alog_attachable~detach.
  PROTECTED SECTION.
    METHODS:
      "! Internal implementation of zif_alog_logger-&gtentry_msg( ) to do the logging
      "!

      "! Implement in non abstract subclasses.
      "!

      "! @parameter iv_text | Message text
      "! @parameter io_type | Type of the message
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_msgty | Message type unsupported
      "! @raising zcx_alog_argument_null | io_type cannot be null
      entry_internal ABSTRACT IMPORTING iv_text TYPE csequence
                                        io_type TYPE REF TO zcl_alog_entry_type
                              RAISING   zcx_alog_logging_failed
                                        zcx_alog_unsupported_msgty
                                        zcx_alog_argument_null,
      "! Inform attached loggers
      "! @parameter iv_text | Message text
      "! @parameter io_type | Message type
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_msgty |
      "! @raising zcx_alog_argument_null |
      inform_attached_loggers IMPORTING iv_text TYPE csequence
                                        io_type TYPE REF TO zcl_alog_entry_type
                              RAISING   zcx_alog_logging_failed
                                        zcx_alog_unsupported_msgty
                                        zcx_alog_argument_null.
    DATA:
      mt_attached_loggers TYPE HASHED TABLE OF REF TO zif_alog_logger WITH UNIQUE KEY table_line.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_alog_logger_base IMPLEMENTATION.
  METHOD zif_alog_logger~entry.
    zcx_alog_argument_null=>raise_if_nullpointer( io_object        = io_type
                                                  iv_variable_name = 'IO_TYPE' ).

    inform_attached_loggers( iv_text = iv_text io_type = io_type ).
    entry_internal( iv_text = iv_text io_type = io_type ).
  ENDMETHOD.

  METHOD zif_alog_logger~debug.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_debug ).
  ENDMETHOD.

  METHOD zif_alog_logger~error.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_error ).
  ENDMETHOD.

  METHOD zif_alog_logger~exception.
    entry( iv_text = ix_ex->get_text( ) io_type = zcl_alog_entry_type=>go_error ).
  ENDMETHOD.

  METHOD zif_alog_logger~info.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_info ).
  ENDMETHOD.

  METHOD zif_alog_logger~warning.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_warning ).
  ENDMETHOD.

  METHOD zif_alog_attachable~attach.
    zcx_alog_argument_null=>raise_if_nullpointer( io_object        = ii_logger
                                                  iv_variable_name = 'II_LOGGER' ).
    TRY.
        INSERT ii_logger INTO TABLE mt_attached_loggers.
        ASSERT sy-subrc = 0.
      CATCH cx_sy_itab_duplicate_key INTO DATA(lx_ex).
        RAISE EXCEPTION TYPE zcx_alog_already_attached
          EXPORTING
            ix_previous = lx_ex.
    ENDTRY.
  ENDMETHOD.

  METHOD zif_alog_attachable~detach.
    zcx_alog_argument_null=>raise_if_nullpointer( io_object        = ii_logger
                                                  iv_variable_name = 'II_LOGGER' ).
    DELETE TABLE mt_attached_loggers WITH TABLE KEY table_line = ii_logger.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_alog_not_attached.
    ENDIF.
  ENDMETHOD.

  METHOD inform_attached_loggers.
    LOOP AT mt_attached_loggers ASSIGNING FIELD-SYMBOL(<li_logger>).
      <li_logger>->entry( iv_text = iv_text io_type = io_type ).
    ENDLOOP.
  ENDMETHOD.
ENDCLASS.

"! Logger base class
"!

"! Inherit from this class and implement entry_internal for the logging logic.
"!

CLASS zcl_alog_logger_base DEFINITION
  PUBLIC
  ABSTRACT
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES:
      zif_alog_logger FINAL METHODS entry,
      zif_alog_attachable.
    ALIASES:
      debug FOR zif_alog_logger~debug,
      entry FOR zif_alog_logger~entry,
      error FOR zif_alog_logger~error,
      exception FOR zif_alog_logger~exception,
      info FOR zif_alog_logger~info,
      warning FOR zif_alog_logger~warning,
      attach FOR zif_alog_attachable~attach,
      detach FOR zif_alog_attachable~detach.
  PROTECTED SECTION.
    METHODS:
      "! Internal implementation of zif_alog_logger-&gtentry_msg( ) to do the logging
      "!

      "! Implement in non abstract subclasses.
      "!

      "! @parameter iv_text | Message text
      "! @parameter io_type | Type of the message
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_msgty | Message type unsupported
      "! @raising zcx_alog_argument_null | io_type cannot be null
      entry_internal ABSTRACT IMPORTING iv_text TYPE csequence
                                        io_type TYPE REF TO zcl_alog_entry_type
                              RAISING   zcx_alog_logging_failed
                                        zcx_alog_unsupported_msgty
                                        zcx_alog_argument_null,
      "! Inform attached loggers
      "! @parameter iv_text | Message text
      "! @parameter io_type | Message type
      "! @raising zcx_alog_logging_failed | Logging failed
      "! @raising zcx_alog_unsupported_msgty | Unsupported message type
      "! @raising zcx_alog_argument_null | io_type cannot be null
      inform_attached_loggers IMPORTING iv_text TYPE csequence
                                        io_type TYPE REF TO zcl_alog_entry_type
                              RAISING   zcx_alog_logging_failed
                                        zcx_alog_unsupported_msgty
                                        zcx_alog_argument_null.
    DATA:
      mt_attached_loggers TYPE HASHED TABLE OF REF TO zif_alog_logger WITH UNIQUE KEY table_line.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_alog_logger_base IMPLEMENTATION.
  METHOD zif_alog_logger~entry.
    zcx_alog_argument_null=>raise_if_nullpointer( io_object        = io_type
                                                  iv_variable_name = 'IO_TYPE' ).

    inform_attached_loggers( iv_text = iv_text io_type = io_type ).
    entry_internal( iv_text = iv_text io_type = io_type ).
  ENDMETHOD.

  METHOD zif_alog_logger~debug.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_debug ).
  ENDMETHOD.

  METHOD zif_alog_logger~error.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_error ).
  ENDMETHOD.

  METHOD zif_alog_logger~exception.
    entry( iv_text = ix_ex->get_text( ) io_type = zcl_alog_entry_type=>go_error ).
  ENDMETHOD.

  METHOD zif_alog_logger~info.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_info ).
  ENDMETHOD.

  METHOD zif_alog_logger~warning.
    entry( iv_text = iv_text io_type = zcl_alog_entry_type=>go_warning ).
  ENDMETHOD.

  METHOD zif_alog_attachable~attach.
    zcx_alog_argument_null=>raise_if_nullpointer( io_object        = ii_logger
                                                  iv_variable_name = 'II_LOGGER' ).
    TRY.
        INSERT ii_logger INTO TABLE mt_attached_loggers.
        ASSERT sy-subrc = 0.
      CATCH cx_sy_itab_duplicate_key INTO DATA(lx_ex).
        RAISE EXCEPTION TYPE zcx_alog_already_attached
          EXPORTING
            ix_previous = lx_ex.
    ENDTRY.
  ENDMETHOD.

  METHOD zif_alog_attachable~detach.
    zcx_alog_argument_null=>raise_if_nullpointer( io_object        = ii_logger
                                                  iv_variable_name = 'II_LOGGER' ).
    DELETE TABLE mt_attached_loggers WITH TABLE KEY table_line = ii_logger.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_alog_not_attached.
    ENDIF.
  ENDMETHOD.

  METHOD inform_attached_loggers.
    LOOP AT mt_attached_loggers ASSIGNING FIELD-SYMBOL(<li_logger>).
      <li_logger>->entry( iv_text = iv_text io_type = io_type ).
    ENDLOOP.
  ENDMETHOD.
ENDCLASS.

Fix missing documentation

Fix missing documentation


class ZCL_MOCKUP_LOADER_STUB_BASE definition
  public
  abstract
  create public .

  public section.

    types:
      begin of ty_mock_config,
        method_name     type abap_methname,
        mock_name       type string,
        load_strict     type abap_bool,
        corresponding   type abap_bool,
        sift_param      type string,
        mock_tab_key    type abap_compname,
        output_param    type abap_parmname,
        output_pkind    type abap_parmkind,
        output_type     type ref to cl_abap_datadescr,
        as_proxy        type abap_bool,
        field_only      type abap_parmname,
        const_value     type string,
      end of ty_mock_config .
    types:
      tt_mock_config type standard table of ty_mock_config with key method_name .

    types:
      begin of ty_control,
        method_name     type abap_methname,
        is_disabled     type abap_bool,
        call_count      type i,
      end of ty_control .
    types:
      tt_control type standard table of ty_control with key method_name .

    interfaces ZIF_MOCKUP_LOADER_STUB_CONTROL.

    methods constructor
      importing
        !it_config type tt_mock_config
        !io_ml type ref to zcl_mockup_loader
        !io_proxy_target type ref to object optional .
  protected section.
    methods get_mock_data
      importing
        i_method_name type abap_methname
        i_sift_value  type any optional
      returning value(r_data) type ref to data
      raising zcx_mockup_loader_error.

    methods is_disabled
      importing
        i_method   type abap_methname
      returning
        value(rv_disabled) type abap_bool.

    methods increment_call_count
      importing
        i_method   type abap_methname.

    data mt_config type tt_mock_config.
    data mt_control type tt_control.
    data mo_ml      type ref to zcl_mockup_loader.
    data mo_proxy_target type ref to object .
  private section.

    methods set_disabled
      importing
        i_method   type abap_methname
        i_disabled type abap_bool.

    methods get_control_for_method
      importing
        i_method   type abap_methname
      returning
        value(rv_ref) type ref to ty_control.
ENDCLASS.

CLASS ZCL_MOCKUP_LOADER_STUB_BASE IMPLEMENTATION.

  method constructor.
    mt_config       = it_config.
    mo_ml           = io_ml.
    mo_proxy_target = io_proxy_target.
  endmethod.

  method get_control_for_method.

    field-symbols <ctl> like line of mt_control.
    read table mt_control assigning <ctl> with key method_name = i_method.
    if sy-subrc <> 0.
      append initial line to mt_control assigning <ctl>.
      <ctl>-method_name = i_method.
    endif.
    get reference of <ctl> into rv_ref.

  endmethod.

  method get_mock_data.
    " find config
    field-symbols <conf> like line of mt_config.
    read table mt_config with key method_name = i_method_name assigning <conf>.
    if <conf> is not assigned.
      return.
    endif.

    " if sift, build filter
    data ls_filter type zcl_mockup_loader_utils=>ty_filter.
    if <conf>-sift_param is not initial.
      data ld_type type ref to cl_abap_typedescr.
      ld_type = cl_abap_typedescr=>describe_by_data( i_sift_value ).
      if ld_type->kind = ld_type->kind_elem.
        ls_filter = zcl_mockup_loader_utils=>conv_single_val_to_filter(
          i_where = <conf>-mock_tab_key
          i_value = i_sift_value ).
      elseif ld_type->kind = ld_type->kind_table.
        ls_filter = zcl_mockup_loader_utils=>conv_range_to_filter(
          i_where = <conf>-mock_tab_key
          i_range = i_sift_value ).
      else.
        zcx_mockup_loader_error=>raise( msg = 'Unexpected sift param type' code = 'US' ).
      endif.
    endif.

    " create data container and load mock
    create data r_data type handle <conf>-output_type.
    mo_ml->load_data(
      exporting
        i_obj    = <conf>-mock_name
        i_strict = <conf>-load_strict
        i_corresponding = boolc( <conf>-field_only is not initial or <conf>-corresponding = abap_true )
        i_where  = ls_filter
      importing
        e_container = r_data ).

    if <conf>-field_only is not initial.
      field-symbols <data> type any.
      field-symbols <field> type any.
      assign r_data->* to <data>.
      assign component <conf>-field_only of structure <data> to <field>.
      data lr_field type ref to data.
      create data lr_field like <field>.
      assign lr_field->* to <data>.
      <data> = <field>.
      r_data = lr_field. " smoking upside down in the sky ...
    endif.

  endmethod.

  method increment_call_count.
    data lr_control type ref to ty_control.
    lr_control = get_control_for_method( i_method ).
    lr_control->call_count = lr_control->call_count + 1.
  endmethod.

  method is_disabled.
    data lr_control type ref to ty_control.
    lr_control = get_control_for_method( i_method ).
    rv_disabled = lr_control->is_disabled.
  endmethod.

  method set_disabled.

    data lr_control type ref to ty_control.
    field-symbols <conf> like line of mt_config.

    if i_method is not initial.
      lr_control = get_control_for_method( i_method ).
      lr_control->is_disabled = i_disabled.
    else.
      loop at mt_config assigning <conf>.
        lr_control = get_control_for_method( <conf>-method_name ).
        lr_control->is_disabled = i_disabled.
      endloop.
    endif.

  endmethod.

  method zif_mockup_loader_stub_control~disable.
    set_disabled(
      i_method = i_method
      i_disabled = abap_true ).
  endmethod.

  method zif_mockup_loader_stub_control~enable.
    set_disabled(
      i_method = i_method
      i_disabled = abap_false ).
  endmethod.

  method zif_mockup_loader_stub_control~get_call_count.
    data lr_control type ref to ty_control.
    lr_control = get_control_for_method( i_method ).
    rv_call_count = lr_control->call_count.
  endmethod.
ENDCLASS.

class ZCL_MOCKUP_LOADER_STUB_BASE definition
  public
  abstract
  create public .

  public section.

    types:
      begin of ty_mock_config,
        method_name     type abap_methname,
        mock_name       type string,
        load_strict     type abap_bool,
        corresponding   type abap_bool,
        sift_param      type string,
        mock_tab_key    type abap_compname,
        output_param    type abap_parmname,
        output_pkind    type abap_parmkind,
        output_type     type ref to cl_abap_datadescr,
        as_proxy        type abap_bool,
        field_only      type abap_parmname,
        const_value     type string,
      end of ty_mock_config .
    types:
      tt_mock_config type standard table of ty_mock_config with key method_name .

    types:
      begin of ty_control,
        method_name     type abap_methname,
        is_disabled     type abap_bool,
        call_count      type i,
      end of ty_control .
    types:
      tt_control type standard table of ty_control with key method_name .

    interfaces ZIF_MOCKUP_LOADER_STUB_CONTROL.

    methods constructor
      importing
        !it_config type tt_mock_config
        !io_ml type ref to zcl_mockup_loader
        !io_proxy_target type ref to object optional .
  protected section.
    methods get_mock_data
      importing
        i_method_name type abap_methname
        i_sift_value  type any optional
      returning value(r_data) type ref to data
      raising zcx_mockup_loader_error.

    methods is_disabled
      importing
        i_method   type abap_methname
      returning
        value(rv_disabled) type abap_bool.

    methods increment_call_count
      importing
        i_method   type abap_methname.

    data mt_config type tt_mock_config.
    data mt_control type tt_control.
    data mo_ml      type ref to zcl_mockup_loader.
    data mo_proxy_target type ref to object .
  private section.

    methods set_disabled
      importing
        i_method   type abap_methname
        i_disabled type abap_bool.

    methods get_control_for_method
      importing
        i_method   type abap_methname
      returning
        value(rv_ref) type ref to ty_control.
ENDCLASS.

CLASS ZCL_MOCKUP_LOADER_STUB_BASE IMPLEMENTATION.

  method constructor.
    mt_config       = it_config.
    mo_ml           = io_ml.
    mo_proxy_target = io_proxy_target.
  endmethod.

  method get_control_for_method.

    field-symbols <ctl> like line of mt_control.
    data l_method like i_method.
    l_method = to_upper( i_method ).

    read table mt_control assigning <ctl> with key method_name = l_method.
    if sy-subrc <> 0.
      append initial line to mt_control assigning <ctl>.
      <ctl>-method_name = l_method.
    endif.
    get reference of <ctl> into rv_ref.

  endmethod.

  method get_mock_data.
    " find config
    field-symbols <conf> like line of mt_config.
    read table mt_config with key method_name = i_method_name assigning <conf>.
    if <conf> is not assigned.
      return.
    endif.

    " if sift, build filter
    data ls_filter type zcl_mockup_loader_utils=>ty_filter.
    if <conf>-sift_param is not initial.
      data ld_type type ref to cl_abap_typedescr.
      ld_type = cl_abap_typedescr=>describe_by_data( i_sift_value ).
      if ld_type->kind = ld_type->kind_elem.
        ls_filter = zcl_mockup_loader_utils=>conv_single_val_to_filter(
          i_where = <conf>-mock_tab_key
          i_value = i_sift_value ).
      elseif ld_type->kind = ld_type->kind_table.
        ls_filter = zcl_mockup_loader_utils=>conv_range_to_filter(
          i_where = <conf>-mock_tab_key
          i_range = i_sift_value ).
      else.
        zcx_mockup_loader_error=>raise( msg = 'Unexpected sift param type' code = 'US' ).
      endif.
    endif.

    " create data container and load mock
    create data r_data type handle <conf>-output_type.
    mo_ml->load_data(
      exporting
        i_obj    = <conf>-mock_name
        i_strict = <conf>-load_strict
        i_corresponding = boolc( <conf>-field_only is not initial or <conf>-corresponding = abap_true )
        i_where  = ls_filter
      importing
        e_container = r_data ).

    if <conf>-field_only is not initial.
      field-symbols <data> type any.
      field-symbols <field> type any.
      assign r_data->* to <data>.
      assign component <conf>-field_only of structure <data> to <field>.
      data lr_field type ref to data.
      create data lr_field like <field>.
      assign lr_field->* to <data>.
      <data> = <field>.
      r_data = lr_field. " smoking upside down in the sky ...
    endif.

  endmethod.

  method increment_call_count.
    data lr_control type ref to ty_control.
    lr_control = get_control_for_method( i_method ).
    lr_control->call_count = lr_control->call_count + 1.
  endmethod.

  method is_disabled.
    data lr_control type ref to ty_control.
    lr_control = get_control_for_method( i_method ).
    rv_disabled = lr_control->is_disabled.
  endmethod.

  method set_disabled.

    data lr_control type ref to ty_control.
    field-symbols <conf> like line of mt_config.

    if i_method is not initial.
      lr_control = get_control_for_method( i_method ).
      lr_control->is_disabled = i_disabled.
    else.
      loop at mt_config assigning <conf>.
        lr_control = get_control_for_method( <conf>-method_name ).
        lr_control->is_disabled = i_disabled.
      endloop.
    endif.

  endmethod.

  method zif_mockup_loader_stub_control~disable.
    set_disabled(
      i_method = i_method
      i_disabled = abap_true ).
  endmethod.

  method zif_mockup_loader_stub_control~enable.
    set_disabled(
      i_method = i_method
      i_disabled = abap_false ).
  endmethod.

  method zif_mockup_loader_stub_control~get_call_count.
    data lr_control type ref to ty_control.
    lr_control = get_control_for_method( i_method ).
    rv_call_count = lr_control->call_count.
  endmethod.
ENDCLASS.

fix get_control_for_method uppercase meth name


CLASS zcl_abapgit_gui_page_main DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC INHERITING FROM zcl_abapgit_gui_page.

  PUBLIC SECTION.
    INTERFACES: zif_abapgit_gui_hotkeys.
    METHODS:
      constructor
        RAISING zcx_abapgit_exception,
      zif_abapgit_gui_event_handler~on_event REDEFINITION.

  PROTECTED SECTION.
    METHODS:
      render_content REDEFINITION.

  PRIVATE SECTION.
    CONSTANTS:
      BEGIN OF c_actions,
        show         TYPE string VALUE 'show' ##NO_TEXT,
        overview     TYPE string VALUE 'overview',
        select       TYPE string VALUE 'select',
        apply_filter TYPE string VALUE 'apply_filter',
        abapgit_home TYPE string VALUE 'abapgit_home',
      END OF c_actions.

    DATA: mo_repo_overview TYPE REF TO zcl_abapgit_gui_page_repo_over,
          mv_repo_key      TYPE zif_abapgit_persistence=>ty_value.

    METHODS build_main_menu
      RETURNING VALUE(ro_menu) TYPE REF TO zcl_abapgit_html_toolbar.

ENDCLASS.

CLASS zcl_abapgit_gui_page_main IMPLEMENTATION.

  METHOD build_main_menu.

    CREATE OBJECT ro_menu EXPORTING iv_id = 'toolbar-main'.

    ro_menu->add(
      iv_txt = zcl_abapgit_gui_buttons=>new_online( )
      iv_act = zif_abapgit_definitions=>c_action-repo_newonline
    )->add(
      iv_txt = zcl_abapgit_gui_buttons=>new_offline( )
      iv_act = zif_abapgit_definitions=>c_action-repo_newoffline
    )->add(
      iv_txt = zcl_abapgit_gui_buttons=>settings( )
      iv_act = zif_abapgit_definitions=>c_action-go_settings
    )->add(
      iv_txt = zcl_abapgit_gui_buttons=>advanced( )
      iv_title = 'Utilities'
      io_sub = zcl_abapgit_gui_chunk_lib=>advanced_submenu( )
    )->add(
      iv_txt = zcl_abapgit_gui_buttons=>help( )
      iv_title = 'Help'
      io_sub = zcl_abapgit_gui_chunk_lib=>help_submenu( ) ).

  ENDMETHOD.

  METHOD constructor.
    super->constructor( ).
    ms_control-page_menu  = build_main_menu( ).
    ms_control-page_title = 'Repository List'.
  ENDMETHOD.

  METHOD render_content.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.
    gui_services( )->get_hotkeys_ctl( )->register_hotkeys( me ).

    IF mo_repo_overview IS INITIAL.
      CREATE OBJECT mo_repo_overview.
    ENDIF.

    ri_html->add( mo_repo_overview->zif_abapgit_gui_renderable~render( ) ).

    register_deferred_script( zcl_abapgit_gui_chunk_lib=>render_repo_palette( c_actions-select ) ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.

    DATA: lv_key TYPE zif_abapgit_persistence=>ty_value.

    CASE ii_event->mv_action.
      WHEN c_actions-abapgit_home.
        CLEAR mv_repo_key.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
      WHEN c_actions-select.

        lv_key = ii_event->query( )->get( 'KEY' ).
        zcl_abapgit_persistence_user=>get_instance( )->set_repo_show( lv_key ).

        TRY.
            zcl_abapgit_repo_srv=>get_instance( )->get( lv_key )->refresh( ).
          CATCH zcx_abapgit_exception ##NO_HANDLER.
        ENDTRY.

        mv_repo_key = lv_key.
        CREATE OBJECT rs_handled-page TYPE zcl_abapgit_gui_page_repo_view
          EXPORTING
            iv_key = lv_key.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page.

      WHEN zif_abapgit_definitions=>c_action-change_order_by.

        mo_repo_overview->set_order_by( ii_event->query( )->get( 'ORDERBY' ) ).
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.

      WHEN zif_abapgit_definitions=>c_action-direction.

        mo_repo_overview->set_order_direction(
          boolc( ii_event->query( )->get( 'DIRECTION' ) = 'DESCENDING' ) ).
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.

      WHEN c_actions-apply_filter.

        mo_repo_overview->set_filter( ii_event->mt_postdata ).
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.

      WHEN zif_abapgit_definitions=>c_action-go_patch.

        lv_key = ii_event->query( )->get( 'KEY' ).
        CREATE OBJECT rs_handled-page TYPE zcl_abapgit_gui_page_patch
          EXPORTING
            iv_key = lv_key.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page.

      WHEN zif_abapgit_definitions=>c_action-repo_settings.

        lv_key = ii_event->query( )->get( 'KEY' ).
        CREATE OBJECT rs_handled-page TYPE zcl_abapgit_gui_page_repo_sett
          EXPORTING
            io_repo = zcl_abapgit_repo_srv=>get_instance( )->get( lv_key ).
        rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page.

      WHEN OTHERS.

        rs_handled = super->zif_abapgit_gui_event_handler~on_event( ii_event ).

    ENDCASE.

  ENDMETHOD.

  METHOD zif_abapgit_gui_hotkeys~get_hotkey_actions.

    DATA: ls_hotkey_action LIKE LINE OF rt_hotkey_actions.

    ls_hotkey_action-ui_component = 'Main'.

    ls_hotkey_action-description   = |abapGit settings|.
    ls_hotkey_action-action = zif_abapgit_definitions=>c_action-go_settings.
    ls_hotkey_action-hotkey = |x|.
    INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.

    ls_hotkey_action-description   = |New online repository|.
    ls_hotkey_action-action = zif_abapgit_definitions=>c_action-repo_newonline.
    ls_hotkey_action-hotkey = |n|.
    INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.

    ls_hotkey_action-description   = |New offline repository|.
    ls_hotkey_action-action = zif_abapgit_definitions=>c_action-repo_newoffline.
    ls_hotkey_action-hotkey = |f|.
    INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_gui_page_main DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC INHERITING FROM zcl_abapgit_gui_page.

  PUBLIC SECTION.
    INTERFACES: zif_abapgit_gui_hotkeys.
    METHODS:
      constructor
        RAISING zcx_abapgit_exception,
      zif_abapgit_gui_event_handler~on_event REDEFINITION.

  PROTECTED SECTION.
    METHODS:
      render_content REDEFINITION.

  PRIVATE SECTION.
    CONSTANTS:
      BEGIN OF c_actions,
        show         TYPE string VALUE 'show' ##NO_TEXT,
        overview     TYPE string VALUE 'overview',
        select       TYPE string VALUE 'select',
        apply_filter TYPE string VALUE 'apply_filter',
        abapgit_home TYPE string VALUE 'abapgit_home',
      END OF c_actions.

    DATA: mo_repo_overview TYPE REF TO zcl_abapgit_gui_page_repo_over,
          mv_repo_key      TYPE zif_abapgit_persistence=>ty_value.

    METHODS build_main_menu
      RETURNING VALUE(ro_menu) TYPE REF TO zcl_abapgit_html_toolbar.

ENDCLASS.

CLASS zcl_abapgit_gui_page_main IMPLEMENTATION.

  METHOD build_main_menu.

    CREATE OBJECT ro_menu EXPORTING iv_id = 'toolbar-main'.

    ro_menu->add(
      iv_txt = zcl_abapgit_gui_buttons=>new_online( )
      iv_act = zif_abapgit_definitions=>c_action-repo_newonline
    )->add(
      iv_txt = zcl_abapgit_gui_buttons=>new_offline( )
      iv_act = zif_abapgit_definitions=>c_action-repo_newoffline
    )->add(
      iv_txt = zcl_abapgit_gui_buttons=>settings( )
      iv_act = zif_abapgit_definitions=>c_action-go_settings
    )->add(
      iv_txt = zcl_abapgit_gui_buttons=>advanced( )
      iv_title = 'Utilities'
      io_sub = zcl_abapgit_gui_chunk_lib=>advanced_submenu( )
    )->add(
      iv_txt = zcl_abapgit_gui_buttons=>help( )
      iv_title = 'Help'
      io_sub = zcl_abapgit_gui_chunk_lib=>help_submenu( ) ).

  ENDMETHOD.

  METHOD constructor.
    super->constructor( ).
    ms_control-page_menu  = build_main_menu( ).
    ms_control-page_title = 'Repository List'.
  ENDMETHOD.

  METHOD render_content.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.
    gui_services( )->get_hotkeys_ctl( )->register_hotkeys( me ).

    IF mo_repo_overview IS INITIAL.
      CREATE OBJECT mo_repo_overview.
    ENDIF.

    ri_html->add( mo_repo_overview->zif_abapgit_gui_renderable~render( ) ).

    register_deferred_script( zcl_abapgit_gui_chunk_lib=>render_repo_palette( c_actions-select ) ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.

    DATA: lv_key TYPE zif_abapgit_persistence=>ty_value.

    CASE ii_event->mv_action.
      WHEN c_actions-abapgit_home.
        CLEAR mv_repo_key.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
      WHEN c_actions-select.

        lv_key = ii_event->query( )->get( 'KEY' ).
        zcl_abapgit_persistence_user=>get_instance( )->set_repo_show( lv_key ).

        TRY.
            zcl_abapgit_repo_srv=>get_instance( )->get( lv_key )->refresh( ).
          CATCH zcx_abapgit_exception ##NO_HANDLER.
        ENDTRY.

        mv_repo_key = lv_key.
        CREATE OBJECT rs_handled-page TYPE zcl_abapgit_gui_page_repo_view
          EXPORTING
            iv_key = lv_key.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page.

      WHEN zif_abapgit_definitions=>c_action-change_order_by.

        mo_repo_overview->set_order_by( ii_event->query( )->get( 'ORDERBY' ) ).
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.

      WHEN zif_abapgit_definitions=>c_action-direction.

        mo_repo_overview->set_order_direction(
          boolc( ii_event->query( )->get( 'DIRECTION' ) = 'DESCENDING' ) ).
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.

      WHEN c_actions-apply_filter.

        mo_repo_overview->set_filter( ii_event->mt_postdata ).
        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.

      WHEN zif_abapgit_definitions=>c_action-go_patch.

        lv_key = ii_event->query( )->get( 'KEY' ).
        CREATE OBJECT rs_handled-page TYPE zcl_abapgit_gui_page_patch
          EXPORTING
            iv_key = lv_key.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page.

      WHEN zif_abapgit_definitions=>c_action-repo_settings.

        lv_key = ii_event->query( )->get( 'KEY' ).
        CREATE OBJECT rs_handled-page TYPE zcl_abapgit_gui_page_repo_sett
          EXPORTING
            io_repo = zcl_abapgit_repo_srv=>get_instance( )->get( lv_key ).
        rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page.

      WHEN OTHERS.

        rs_handled = super->zif_abapgit_gui_event_handler~on_event( ii_event ).

    ENDCASE.

  ENDMETHOD.

  METHOD zif_abapgit_gui_hotkeys~get_hotkey_actions.

    DATA: ls_hotkey_action LIKE LINE OF rt_hotkey_actions.

    ls_hotkey_action-ui_component = 'Main'.

    ls_hotkey_action-description   = |abapGit settings|.
    ls_hotkey_action-action = zif_abapgit_definitions=>c_action-go_settings.
    ls_hotkey_action-hotkey = |x|.
    INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.

    ls_hotkey_action-description   = |New online repository|.
    ls_hotkey_action-action = zif_abapgit_definitions=>c_action-repo_newonline.
    ls_hotkey_action-hotkey = |n|.
    INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.

    ls_hotkey_action-description   = |New offline repository|.
    ls_hotkey_action-action = zif_abapgit_definitions=>c_action-repo_newoffline.
    ls_hotkey_action-hotkey = |o|.
    INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.

  ENDMETHOD.
ENDCLASS.

Resolve hotkey conflict (#4228)

Resolve hotkey conflict (#4228)

"f" is default for vimium-links. Changed "New Offline" to "o".

Co-authored-by: Lars Hvam <721d1b171982cd84b755f6b25130d2b88cd1f696@hotmail.com>


CLASS zcl_abapgit_persistence_user DEFINITION
  PUBLIC
  CREATE PRIVATE .

  PUBLIC SECTION.

    INTERFACES zif_abapgit_persist_user .

    TYPES ty_favorites TYPE zif_abapgit_persistence=>ty_repo_keys .

    CLASS-METHODS get_instance
      IMPORTING
        !iv_user       TYPE sy-uname DEFAULT sy-uname
      RETURNING
        VALUE(ri_user) TYPE REF TO zif_abapgit_persist_user
      RAISING
        zcx_abapgit_exception .
    METHODS constructor
      IMPORTING
        !iv_user TYPE sy-uname DEFAULT sy-uname
      RAISING
        zcx_abapgit_exception .
  PROTECTED SECTION.
  PRIVATE SECTION.

    TYPES:
      BEGIN OF ty_repo_config,
        url              TYPE zif_abapgit_persistence=>ty_repo-url,
        login            TYPE string,
        git_user         TYPE zif_abapgit_definitions=>ty_git_user,
        last_change_seen TYPE string,
      END OF ty_repo_config .
    TYPES:
      ty_repo_configs TYPE STANDARD TABLE OF ty_repo_config WITH DEFAULT KEY .
    TYPES:
      BEGIN OF ty_user,
        default_git_user TYPE zif_abapgit_definitions=>ty_git_user,
        repo_show        TYPE zif_abapgit_persistence=>ty_repo-key,
        hide_files       TYPE abap_bool,
        changes_only     TYPE abap_bool,
        diff_unified     TYPE abap_bool,
        favorites        TYPE ty_favorites,
        repo_config      TYPE ty_repo_configs,
        settings         TYPE zif_abapgit_definitions=>ty_s_user_settings,
      END OF ty_user .

    DATA mv_user TYPE sy-uname .
    DATA ms_user TYPE ty_user.
    CLASS-DATA gi_current_user TYPE REF TO zif_abapgit_persist_user .

    METHODS from_xml
      IMPORTING
        !iv_xml        TYPE string
      RETURNING
        VALUE(rs_user) TYPE ty_user
      RAISING
        zcx_abapgit_exception .
    METHODS read
      RAISING
        zcx_abapgit_exception .
    METHODS read_repo_config
      IMPORTING
        !iv_url               TYPE zif_abapgit_persistence=>ty_repo-url
      RETURNING
        VALUE(rs_repo_config) TYPE ty_repo_config
      RAISING
        zcx_abapgit_exception .
    METHODS to_xml
      IMPORTING
        !is_user      TYPE ty_user
      RETURNING
        VALUE(rv_xml) TYPE string .
    METHODS update
      RAISING
        zcx_abapgit_exception .
    METHODS update_repo_config
      IMPORTING
        !iv_url         TYPE zif_abapgit_persistence=>ty_repo-url
        !is_repo_config TYPE ty_repo_config
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_PERSISTENCE_USER IMPLEMENTATION.

  METHOD constructor.
    mv_user = iv_user.
    read( ).
  ENDMETHOD.

  METHOD from_xml.

    DATA: lv_xml TYPE string.

    lv_xml = iv_xml.

* fix downward compatibility
    REPLACE ALL OCCURRENCES OF '<_--28C_TYPE_USER_--29>' IN lv_xml WITH '<USER>'.
    REPLACE ALL OCCURRENCES OF '</_--28C_TYPE_USER_--29>' IN lv_xml WITH '</USER>'.

    CALL TRANSFORMATION id
      OPTIONS value_handling = 'accept_data_loss'
      SOURCE XML lv_xml
      RESULT user = rs_user.
  ENDMETHOD.

  METHOD get_instance.

    IF iv_user = sy-uname ##USER_OK.
      IF gi_current_user IS NOT BOUND.
        CREATE OBJECT gi_current_user TYPE zcl_abapgit_persistence_user.
      ENDIF.
      ri_user = gi_current_user.
    ELSE.
      CREATE OBJECT ri_user TYPE zcl_abapgit_persistence_user
        EXPORTING
          iv_user = iv_user.
    ENDIF.

  ENDMETHOD.

  METHOD read.

    DATA: lv_xml TYPE string.

    TRY.
        lv_xml = zcl_abapgit_persistence_db=>get_instance( )->read(
          iv_type  = zcl_abapgit_persistence_db=>c_type_user
          iv_value = mv_user ).
      CATCH zcx_abapgit_not_found.
        RETURN.
    ENDTRY.

    ms_user = from_xml( lv_xml ).

  ENDMETHOD.

  METHOD read_repo_config.
    READ TABLE ms_user-repo_config INTO rs_repo_config WITH KEY url = to_lower( iv_url ).
  ENDMETHOD.

  METHOD to_xml.
    CALL TRANSFORMATION id
      SOURCE user = is_user
      RESULT XML rv_xml.
  ENDMETHOD.

  METHOD update.

    DATA: lv_xml TYPE string.

    lv_xml = to_xml( ms_user ).

    zcl_abapgit_persistence_db=>get_instance( )->modify(
      iv_type  = zcl_abapgit_persistence_db=>c_type_user
      iv_value = mv_user
      iv_data  = lv_xml ).

    COMMIT WORK AND WAIT.

  ENDMETHOD.

  METHOD update_repo_config.

    DATA: lv_key  TYPE string.

    FIELD-SYMBOLS <ls_repo_config> TYPE ty_repo_config.

    lv_key  = to_lower( iv_url ).

    READ TABLE ms_user-repo_config ASSIGNING <ls_repo_config> WITH KEY url = lv_key.
    IF sy-subrc IS NOT INITIAL.
      APPEND INITIAL LINE TO ms_user-repo_config ASSIGNING <ls_repo_config>.
    ENDIF.
    <ls_repo_config>     = is_repo_config.
    <ls_repo_config>-url = lv_key.

    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_changes_only.

    rv_changes_only = ms_user-changes_only.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_default_git_user_email.

    rv_email = ms_user-default_git_user-email.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_default_git_user_name.

    rv_username = ms_user-default_git_user-name.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_diff_unified.

    rv_diff_unified = ms_user-diff_unified.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_favorites.

    rt_favorites = ms_user-favorites.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_hide_files.

    rv_hide = ms_user-hide_files.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_repo_git_user_email.

    rv_email = read_repo_config( iv_url )-git_user-email.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_repo_git_user_name.

    rv_username = read_repo_config( iv_url )-git_user-name.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_repo_last_change_seen.

    rv_version = read_repo_config( iv_url )-last_change_seen.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_repo_login.

    rv_login = read_repo_config( iv_url )-login.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_repo_show.

    DATA lo_repo TYPE REF TO zcl_abapgit_repo.

    rv_key = ms_user-repo_show.

    " Check if repo exists
    TRY.
        lo_repo = zcl_abapgit_repo_srv=>get_instance( )->get( rv_key ).
      CATCH zcx_abapgit_exception.
        " remove invalid key
        CLEAR rv_key.
        zif_abapgit_persist_user~set_repo_show( rv_key ).
    ENDTRY.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_settings.

    rs_user_settings = ms_user-settings.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~is_favorite_repo.

    READ TABLE ms_user-favorites TRANSPORTING NO FIELDS
      WITH KEY table_line = iv_repo_key.

    rv_yes = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_default_git_user_email.

    ms_user-default_git_user-email = iv_email.
    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_default_git_user_name.

    ms_user-default_git_user-name = iv_username.
    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_repo_git_user_email.

    DATA: ls_repo_config TYPE ty_repo_config.

    ls_repo_config                = read_repo_config( iv_url ).
    ls_repo_config-git_user-email = iv_email.
    update_repo_config( iv_url = iv_url
                        is_repo_config = ls_repo_config ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_repo_git_user_name.

    DATA: ls_repo_config TYPE ty_repo_config.

    ls_repo_config               = read_repo_config( iv_url ).
    ls_repo_config-git_user-name = iv_username.
    update_repo_config( iv_url = iv_url
                        is_repo_config = ls_repo_config ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_repo_last_change_seen.

    DATA: ls_repo_config TYPE ty_repo_config.

    ls_repo_config                  = read_repo_config( iv_url ).
    ls_repo_config-last_change_seen = iv_version.
    update_repo_config( iv_url = iv_url
                        is_repo_config = ls_repo_config ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_repo_login.

    DATA: ls_repo_config TYPE ty_repo_config.

    ls_repo_config       = read_repo_config( iv_url ).
    ls_repo_config-login = iv_login.
    update_repo_config( iv_url = iv_url
                        is_repo_config = ls_repo_config ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_repo_show.

    ms_user-repo_show = iv_key.
    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_settings.

    ms_user-settings = is_user_settings.
    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~toggle_changes_only.

    ms_user-changes_only = boolc( ms_user-changes_only = abap_false ).
    update( ).

    rv_changes_only = ms_user-changes_only.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~toggle_diff_unified.

    ms_user-diff_unified = boolc( ms_user-diff_unified = abap_false ).
    update( ).

    rv_diff_unified = ms_user-diff_unified.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~toggle_favorite.

    READ TABLE ms_user-favorites TRANSPORTING NO FIELDS
      WITH KEY table_line = iv_repo_key.

    IF sy-subrc = 0.
      DELETE ms_user-favorites INDEX sy-tabix.
    ELSE.
      APPEND iv_repo_key TO ms_user-favorites.
    ENDIF.

    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~toggle_hide_files.

    ms_user-hide_files = boolc( ms_user-hide_files = abap_false ).
    update( ).

    rv_hide = ms_user-hide_files.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_persistence_user DEFINITION
  PUBLIC
  CREATE PRIVATE .

  PUBLIC SECTION.

    INTERFACES zif_abapgit_persist_user .

    TYPES ty_favorites TYPE zif_abapgit_persistence=>ty_repo_keys .

    CLASS-METHODS get_instance
      IMPORTING
        !iv_user       TYPE sy-uname DEFAULT sy-uname
      RETURNING
        VALUE(ri_user) TYPE REF TO zif_abapgit_persist_user
      RAISING
        zcx_abapgit_exception .
    METHODS constructor
      IMPORTING
        !iv_user TYPE sy-uname DEFAULT sy-uname
      RAISING
        zcx_abapgit_exception .
  PROTECTED SECTION.
  PRIVATE SECTION.

    TYPES:
      BEGIN OF ty_repo_config,
        url              TYPE zif_abapgit_persistence=>ty_repo-url,
        login            TYPE string,
        git_user         TYPE zif_abapgit_definitions=>ty_git_user,
        last_change_seen TYPE string,
      END OF ty_repo_config .
    TYPES:
      ty_repo_configs TYPE STANDARD TABLE OF ty_repo_config WITH DEFAULT KEY .
    TYPES:
      BEGIN OF ty_user,
        default_git_user TYPE zif_abapgit_definitions=>ty_git_user,
        repo_show        TYPE zif_abapgit_persistence=>ty_repo-key,
        hide_files       TYPE abap_bool,
        changes_only     TYPE abap_bool,
        diff_unified     TYPE abap_bool,
        favorites        TYPE ty_favorites,
        repo_config      TYPE ty_repo_configs,
        settings         TYPE zif_abapgit_definitions=>ty_s_user_settings,
      END OF ty_user .

    DATA mv_user TYPE sy-uname .
    DATA ms_user TYPE ty_user.
    CLASS-DATA gi_current_user TYPE REF TO zif_abapgit_persist_user .

    METHODS from_xml
      IMPORTING
        !iv_xml        TYPE string
      RETURNING
        VALUE(rs_user) TYPE ty_user
      RAISING
        zcx_abapgit_exception .
    METHODS read
      RAISING
        zcx_abapgit_exception .
    METHODS read_repo_config
      IMPORTING
        !iv_url               TYPE zif_abapgit_persistence=>ty_repo-url
      RETURNING
        VALUE(rs_repo_config) TYPE ty_repo_config
      RAISING
        zcx_abapgit_exception .
    METHODS to_xml
      IMPORTING
        !is_user      TYPE ty_user
      RETURNING
        VALUE(rv_xml) TYPE string .
    METHODS update
      RAISING
        zcx_abapgit_exception .
    METHODS update_repo_config
      IMPORTING
        !iv_url         TYPE zif_abapgit_persistence=>ty_repo-url
        !is_repo_config TYPE ty_repo_config
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_PERSISTENCE_USER IMPLEMENTATION.

  METHOD constructor.
    mv_user = iv_user.
    read( ).
  ENDMETHOD.

  METHOD from_xml.

    DATA: lv_xml TYPE string.

    lv_xml = iv_xml.

* fix downward compatibility
    REPLACE ALL OCCURRENCES OF '<_--28C_TYPE_USER_--29>' IN lv_xml WITH '<USER>'.
    REPLACE ALL OCCURRENCES OF '</_--28C_TYPE_USER_--29>' IN lv_xml WITH '</USER>'.

    CALL TRANSFORMATION id
      OPTIONS value_handling = 'accept_data_loss'
      SOURCE XML lv_xml
      RESULT user = rs_user.
  ENDMETHOD.

  METHOD get_instance.

    IF iv_user = sy-uname ##USER_OK.
      IF gi_current_user IS NOT BOUND.
        CREATE OBJECT gi_current_user TYPE zcl_abapgit_persistence_user.
      ENDIF.
      ri_user = gi_current_user.
    ELSE.
      CREATE OBJECT ri_user TYPE zcl_abapgit_persistence_user
        EXPORTING
          iv_user = iv_user.
    ENDIF.

  ENDMETHOD.

  METHOD read.

    DATA: lv_xml TYPE string.

    TRY.
        lv_xml = zcl_abapgit_persistence_db=>get_instance( )->read(
          iv_type  = zcl_abapgit_persistence_db=>c_type_user
          iv_value = mv_user ).
      CATCH zcx_abapgit_not_found.
        RETURN.
    ENDTRY.

    ms_user = from_xml( lv_xml ).

  ENDMETHOD.

  METHOD read_repo_config.
    DATA lv_url TYPE string.
    lv_url = to_lower( iv_url ).
    READ TABLE ms_user-repo_config INTO rs_repo_config WITH KEY url = lv_url.
  ENDMETHOD.

  METHOD to_xml.
    CALL TRANSFORMATION id
      SOURCE user = is_user
      RESULT XML rv_xml.
  ENDMETHOD.

  METHOD update.

    DATA: lv_xml TYPE string.

    lv_xml = to_xml( ms_user ).

    zcl_abapgit_persistence_db=>get_instance( )->modify(
      iv_type  = zcl_abapgit_persistence_db=>c_type_user
      iv_value = mv_user
      iv_data  = lv_xml ).

    COMMIT WORK AND WAIT.

  ENDMETHOD.

  METHOD update_repo_config.

    DATA: lv_key  TYPE string.

    FIELD-SYMBOLS <ls_repo_config> TYPE ty_repo_config.

    lv_key  = to_lower( iv_url ).

    READ TABLE ms_user-repo_config ASSIGNING <ls_repo_config> WITH KEY url = lv_key.
    IF sy-subrc IS NOT INITIAL.
      APPEND INITIAL LINE TO ms_user-repo_config ASSIGNING <ls_repo_config>.
    ENDIF.
    <ls_repo_config>     = is_repo_config.
    <ls_repo_config>-url = lv_key.

    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_changes_only.

    rv_changes_only = ms_user-changes_only.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_default_git_user_email.

    rv_email = ms_user-default_git_user-email.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_default_git_user_name.

    rv_username = ms_user-default_git_user-name.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_diff_unified.

    rv_diff_unified = ms_user-diff_unified.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_favorites.

    rt_favorites = ms_user-favorites.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_hide_files.

    rv_hide = ms_user-hide_files.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_repo_git_user_email.

    rv_email = read_repo_config( iv_url )-git_user-email.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_repo_git_user_name.

    rv_username = read_repo_config( iv_url )-git_user-name.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_repo_last_change_seen.

    rv_version = read_repo_config( iv_url )-last_change_seen.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_repo_login.

    rv_login = read_repo_config( iv_url )-login.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_repo_show.

    DATA lo_repo TYPE REF TO zcl_abapgit_repo.

    rv_key = ms_user-repo_show.

    " Check if repo exists
    TRY.
        lo_repo = zcl_abapgit_repo_srv=>get_instance( )->get( rv_key ).
      CATCH zcx_abapgit_exception.
        " remove invalid key
        CLEAR rv_key.
        zif_abapgit_persist_user~set_repo_show( rv_key ).
    ENDTRY.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~get_settings.

    rs_user_settings = ms_user-settings.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~is_favorite_repo.

    READ TABLE ms_user-favorites TRANSPORTING NO FIELDS
      WITH KEY table_line = iv_repo_key.

    rv_yes = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_default_git_user_email.

    ms_user-default_git_user-email = iv_email.
    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_default_git_user_name.

    ms_user-default_git_user-name = iv_username.
    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_repo_git_user_email.

    DATA: ls_repo_config TYPE ty_repo_config.

    ls_repo_config                = read_repo_config( iv_url ).
    ls_repo_config-git_user-email = iv_email.
    update_repo_config( iv_url = iv_url
                        is_repo_config = ls_repo_config ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_repo_git_user_name.

    DATA: ls_repo_config TYPE ty_repo_config.

    ls_repo_config               = read_repo_config( iv_url ).
    ls_repo_config-git_user-name = iv_username.
    update_repo_config( iv_url = iv_url
                        is_repo_config = ls_repo_config ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_repo_last_change_seen.

    DATA: ls_repo_config TYPE ty_repo_config.

    ls_repo_config                  = read_repo_config( iv_url ).
    ls_repo_config-last_change_seen = iv_version.
    update_repo_config( iv_url = iv_url
                        is_repo_config = ls_repo_config ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_repo_login.

    DATA: ls_repo_config TYPE ty_repo_config.

    ls_repo_config       = read_repo_config( iv_url ).
    ls_repo_config-login = iv_login.
    update_repo_config( iv_url = iv_url
                        is_repo_config = ls_repo_config ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_repo_show.

    ms_user-repo_show = iv_key.
    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~set_settings.

    ms_user-settings = is_user_settings.
    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~toggle_changes_only.

    ms_user-changes_only = boolc( ms_user-changes_only = abap_false ).
    update( ).

    rv_changes_only = ms_user-changes_only.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~toggle_diff_unified.

    ms_user-diff_unified = boolc( ms_user-diff_unified = abap_false ).
    update( ).

    rv_diff_unified = ms_user-diff_unified.

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~toggle_favorite.

    READ TABLE ms_user-favorites TRANSPORTING NO FIELDS
      WITH KEY table_line = iv_repo_key.

    IF sy-subrc = 0.
      DELETE ms_user-favorites INDEX sy-tabix.
    ELSE.
      APPEND iv_repo_key TO ms_user-favorites.
    ENDIF.

    update( ).

  ENDMETHOD.

  METHOD zif_abapgit_persist_user~toggle_hide_files.

    ms_user-hide_files = boolc( ms_user-hide_files = abap_false ).
    update( ).

    rv_hide = ms_user-hide_files.

  ENDMETHOD.
ENDCLASS.

702: Fix ZCL_ABAPGIT_PERSISTENCE_USER->read_repo_config (#4038)

Closes #4036


*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_DOCT
*&---------------------------------------------------------------------*

CLASS lcl_object_doct DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.
    ALIASES mo_files FOR lif_object~mo_files.

  PRIVATE SECTION.
    CONSTANTS: c_id      TYPE dokhl-id VALUE 'TX',
               c_typ     TYPE dokhl-typ VALUE 'E',
               c_version TYPE dokhl-dokversion VALUE '0001',
               c_name    TYPE string VALUE 'DOC'.

    TYPES: BEGIN OF ty_data,
             doctitle TYPE dsyst-doktitle,
             head     TYPE thead,
             lines    TYPE tline_tab,
           END OF ty_data.

    METHODS: read
      RETURNING VALUE(rs_data) TYPE ty_data.

ENDCLASS.                    "lcl_object_msag DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_view IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_doct IMPLEMENTATION.

  METHOD lif_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.  "lif_object~has_changed_since

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
    rs_metadata-delete_tadir = abap_true.
  ENDMETHOD.                    "lif_object~get_metadata

  METHOD read.

    DATA: lv_object TYPE dokhl-object.

    lv_object = ms_item-obj_name.

    CALL FUNCTION 'DOCU_READ'
      EXPORTING
        id       = c_id
        langu    = mv_language
        object   = lv_object
        typ      = c_typ
        version  = c_version
      IMPORTING
        doktitle = rs_data-doctitle
        head     = rs_data-head
      TABLES
        line     = rs_data-lines.

  ENDMETHOD.                    "read

  METHOD lif_object~changed_by.
    rv_user = read( )-head-tdluser.
    IF rv_user IS INITIAL.
      rv_user = c_user_unknown.
    ENDIF.
  ENDMETHOD.                    "lif_object~changed_by

  METHOD lif_object~exists.

    DATA: lv_id     TYPE dokil-id,
          lv_object TYPE dokhl-object.

    lv_object = ms_item-obj_name.

    SELECT SINGLE id FROM dokil INTO lv_id
      WHERE id         = c_id
        AND object     = lv_object.                     "#EC CI_GENBUFF

    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~jump.

    DATA: ls_dokentry TYPE dokentry,
          ls_bcdata   TYPE bdcdata,
          lt_bcdata   TYPE STANDARD TABLE OF bdcdata.

    ls_dokentry-username = sy-uname.
    ls_dokentry-langu    = sy-langu.
    ls_dokentry-class    = c_id.
    MODIFY dokentry FROM ls_dokentry.

    ls_bcdata-program  = 'SAPMSDCU'.
    ls_bcdata-dynpro   = '0100'.
    ls_bcdata-dynbegin = 'X'.
    APPEND ls_bcdata TO lt_bcdata.

    CLEAR ls_bcdata.
    ls_bcdata-fnam     = 'RSDCU-OBJECT7'.
    ls_bcdata-fval     = ms_item-obj_name.
    APPEND ls_bcdata TO lt_bcdata.

    CLEAR ls_bcdata.
    ls_bcdata-fnam = 'BDC_OKCODE'.
    ls_bcdata-fval = '=SHOW'.
    APPEND ls_bcdata TO lt_bcdata.

    CALL FUNCTION 'ABAP4_CALL_TRANSACTION'
      STARTING NEW TASK 'GIT'
      EXPORTING
        tcode     = 'SE61'
        mode_val  = 'E'
      TABLES
        using_tab = lt_bcdata
      EXCEPTIONS
        OTHERS    = 1.

    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from ABAP4_CALL_TRANSACTION, DOCT' ).
    ENDIF.

  ENDMETHOD.                    "jump

  METHOD lif_object~delete.

    DATA: lv_object TYPE dokhl-object.

    lv_object = ms_item-obj_name.

    CALL FUNCTION 'DOCU_DEL'
      EXPORTING
        id       = c_id
        langu    = mv_language
        object   = lv_object
        typ      = c_typ
      EXCEPTIONS
        ret_code = 1
        OTHERS   = 2.
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from DOCU_DEL' ).
    ENDIF.

  ENDMETHOD.                    "delete

  METHOD lif_object~deserialize.

    DATA: ls_data TYPE ty_data.

    io_xml->read( EXPORTING iv_name = c_name
                  CHANGING cg_data = ls_data ).

    CALL FUNCTION 'DOCU_UPDATE'
      EXPORTING
        head    = ls_data-head
        state   = 'A'
        typ     = c_typ
        version = c_version
      TABLES
        line    = ls_data-lines.

  ENDMETHOD.                    "deserialize

  METHOD lif_object~serialize.

    DATA: ls_data TYPE ty_data.

    ls_data = read( ).

    CLEAR: ls_data-head-tdfuser,
           ls_data-head-tdfreles,
           ls_data-head-tdfdate,
           ls_data-head-tdftime,
           ls_data-head-tdluser,
           ls_data-head-tdlreles,
           ls_data-head-tdldate,
           ls_data-head-tdltime.

    io_xml->add( iv_name = c_name
                 ig_data = ls_data ).

  ENDMETHOD.                    "serialize

  METHOD lif_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE lcl_comparison_null.
  ENDMETHOD.

ENDCLASS.                    "lcl_object_msag IMPLEMENTATION

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_DOCT
*&---------------------------------------------------------------------*

CLASS lcl_object_doct DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.
    ALIASES mo_files FOR lif_object~mo_files.

  PRIVATE SECTION.
    CONSTANTS: c_id      TYPE dokhl-id VALUE 'TX',
               c_typ     TYPE dokhl-typ VALUE 'E',
               c_version TYPE dokhl-dokversion VALUE '0001',
               c_name    TYPE string VALUE 'DOC'.

    TYPES: BEGIN OF ty_data,
             doctitle TYPE dsyst-doktitle,
             head     TYPE thead,
             lines    TYPE tline_tab,
           END OF ty_data.

    METHODS: read
      RETURNING VALUE(rs_data) TYPE ty_data.

ENDCLASS.                    "lcl_object_msag DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_view IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_doct IMPLEMENTATION.

  METHOD lif_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.  "lif_object~has_changed_since

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
    rs_metadata-delete_tadir = abap_true.
  ENDMETHOD.                    "lif_object~get_metadata

  METHOD read.

    DATA: lv_object TYPE dokhl-object.

    lv_object = ms_item-obj_name.

    CALL FUNCTION 'DOCU_READ'
      EXPORTING
        id       = c_id
        langu    = mv_language
        object   = lv_object
        typ      = c_typ
        version  = c_version
      IMPORTING
        doktitle = rs_data-doctitle
        head     = rs_data-head
      TABLES
        line     = rs_data-lines.

  ENDMETHOD.                    "read

  METHOD lif_object~changed_by.
    rv_user = read( )-head-tdluser.
    IF rv_user IS INITIAL.
      rv_user = c_user_unknown.
    ENDIF.
  ENDMETHOD.                    "lif_object~changed_by

  METHOD lif_object~exists.

    DATA: lv_id     TYPE dokil-id,
          lv_object TYPE dokhl-object.

    lv_object = ms_item-obj_name.

    SELECT SINGLE id FROM dokil INTO lv_id
      WHERE id         = c_id
        AND object     = lv_object.                     "#EC CI_GENBUFF

    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~jump.

    DATA: ls_dokentry TYPE dokentry,
          ls_bcdata   TYPE bdcdata,
          lt_bcdata   TYPE STANDARD TABLE OF bdcdata.

    " We need to modify dokentry directly, otherwise
    " Batch Input on SE61 wouldn't work because it stores
    " the last seen Document Class in this table. There's
    " no standard function to do this. SE61 does this
    " directly in its dialog modules
    ls_dokentry-username = sy-uname.
    ls_dokentry-langu    = sy-langu.
    ls_dokentry-class    = c_id.
    MODIFY dokentry FROM ls_dokentry.

    ls_bcdata-program  = 'SAPMSDCU'.
    ls_bcdata-dynpro   = '0100'.
    ls_bcdata-dynbegin = 'X'.
    APPEND ls_bcdata TO lt_bcdata.

    CLEAR ls_bcdata.
    ls_bcdata-fnam     = 'RSDCU-OBJECT7'.
    ls_bcdata-fval     = ms_item-obj_name.
    APPEND ls_bcdata TO lt_bcdata.

    CLEAR ls_bcdata.
    ls_bcdata-fnam = 'BDC_OKCODE'.
    ls_bcdata-fval = '=SHOW'.
    APPEND ls_bcdata TO lt_bcdata.

    CALL FUNCTION 'ABAP4_CALL_TRANSACTION'
      STARTING NEW TASK 'GIT'
      EXPORTING
        tcode     = 'SE61'
        mode_val  = 'E'
      TABLES
        using_tab = lt_bcdata
      EXCEPTIONS
        OTHERS    = 1.

    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from ABAP4_CALL_TRANSACTION, DOCT' ).
    ENDIF.

  ENDMETHOD.                    "jump

  METHOD lif_object~delete.

    DATA: lv_object TYPE dokhl-object.

    lv_object = ms_item-obj_name.

    CALL FUNCTION 'DOCU_DEL'
      EXPORTING
        id       = c_id
        langu    = mv_language
        object   = lv_object
        typ      = c_typ
      EXCEPTIONS
        ret_code = 1
        OTHERS   = 2.
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from DOCU_DEL' ).
    ENDIF.

  ENDMETHOD.                    "delete

  METHOD lif_object~deserialize.

    DATA: ls_data TYPE ty_data.

    io_xml->read( EXPORTING iv_name = c_name
                  CHANGING cg_data = ls_data ).

    CALL FUNCTION 'DOCU_UPDATE'
      EXPORTING
        head    = ls_data-head
        state   = 'A'
        typ     = c_typ
        version = c_version
      TABLES
        line    = ls_data-lines.

  ENDMETHOD.                    "deserialize

  METHOD lif_object~serialize.

    DATA: ls_data TYPE ty_data.

    ls_data = read( ).

    CLEAR: ls_data-head-tdfuser,
           ls_data-head-tdfreles,
           ls_data-head-tdfdate,
           ls_data-head-tdftime,
           ls_data-head-tdluser,
           ls_data-head-tdlreles,
           ls_data-head-tdldate,
           ls_data-head-tdltime.

    io_xml->add( iv_name = c_name
                 ig_data = ls_data ).

  ENDMETHOD.                    "serialize

  METHOD lif_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE lcl_comparison_null.
  ENDMETHOD.

ENDCLASS.                    "lcl_object_msag IMPLEMENTATION

add comment DOCT jump

add comment DOCT jump