CLASS zcl_abapgit_object_scp1 DEFINITION
  PUBLIC
  INHERITING FROM zcl_abapgit_objects_super
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES zif_abapgit_object .
  PROTECTED SECTION.

    TYPES:
      BEGIN OF ty_scp1,
        scprattr TYPE scprattr,
        scprtext TYPE STANDARD TABLE OF scprtext WITH DEFAULT KEY,
        scprvals TYPE STANDARD TABLE OF scprvals WITH DEFAULT KEY,
        scprvall TYPE STANDARD TABLE OF scprvall WITH DEFAULT KEY,
        scprreca TYPE STANDARD TABLE OF scprreca WITH DEFAULT KEY,
        scprfldv TYPE STANDARD TABLE OF scprfldv WITH DEFAULT KEY,
      END OF ty_scp1 .

    METHODS dequeue .
    METHODS enqueue
      RAISING
        zcx_abapgit_exception .
    METHODS save
      IMPORTING
        !is_scp1 TYPE ty_scp1
      RAISING
        zcx_abapgit_exception .
    METHODS adjust_inbound
      CHANGING
        !cs_scp1 TYPE ty_scp1 .
    METHODS adjust_outbound
      CHANGING
        !cs_scp1 TYPE ty_scp1 .
    METHODS load
      CHANGING
        !cs_scp1 TYPE ty_scp1 .
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_abapgit_object_scp1 IMPLEMENTATION.

  METHOD adjust_inbound.

    FIELD-SYMBOLS: <ls_scprvals> TYPE scprvals,
                   <ls_scprreca> TYPE scprreca.

* back to internal format
    LOOP AT cs_scp1-scprvals ASSIGNING <ls_scprvals>.
      SHIFT <ls_scprvals>-recnumber RIGHT DELETING TRAILING space.
    ENDLOOP.
    LOOP AT cs_scp1-scprreca ASSIGNING <ls_scprreca>.
      SHIFT <ls_scprreca>-recnumber RIGHT DELETING TRAILING space.
    ENDLOOP.

  ENDMETHOD.

  METHOD adjust_outbound.

    FIELD-SYMBOLS: <ls_scprvals> TYPE scprvals,
                   <ls_scprreca> TYPE scprreca.

* normalize the XML
    LOOP AT cs_scp1-scprvals ASSIGNING <ls_scprvals>.
      CONDENSE <ls_scprvals>-recnumber.
    ENDLOOP.
    LOOP AT cs_scp1-scprreca ASSIGNING <ls_scprreca>.
      CONDENSE <ls_scprreca>-recnumber.
    ENDLOOP.

  ENDMETHOD.

  METHOD dequeue.

    DATA: lv_id TYPE scpr_id.

    lv_id = ms_item-obj_name.

    CALL FUNCTION 'SCPR_SV_DEQUEUE_BCSET'
      EXPORTING
        bcset_id = lv_id.

  ENDMETHOD.

  METHOD enqueue.

    DATA: lv_id TYPE scpr_id.

    lv_id = ms_item-obj_name.

    CALL FUNCTION 'SCPR_SV_ENQUEUE_BCSET'
      EXPORTING
        bcset_id          = lv_id
      EXCEPTIONS
        is_already_locked = 1
        system_failure    = 2
        OTHERS            = 3.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |SCP1 locking error| ).
    ENDIF.

  ENDMETHOD.

  METHOD load.

    CALL FUNCTION 'SCPR_TEXT_GET'
      EXPORTING
        profid        = cs_scp1-scprattr-id
        category      = cs_scp1-scprattr-category
      TABLES
        texts         = cs_scp1-scprtext
      EXCEPTIONS
        no_text_found = 1.

    CALL FUNCTION 'SCPR_TEMPL_DB_VALS_GET_DETAIL'
      EXPORTING
        profid   = cs_scp1-scprattr-id
        category = cs_scp1-scprattr-category
      TABLES
        values   = cs_scp1-scprvals
        valuesl  = cs_scp1-scprvall
        recattr  = cs_scp1-scprreca.

    CALL FUNCTION 'SCPR_TEMPL_DB_FLDTXTVAR_GET'
      EXPORTING
        bcset_id = cs_scp1-scprattr-id
        category = cs_scp1-scprattr-category
      TABLES
        it_fldv  = cs_scp1-scprfldv.

  ENDMETHOD.

  METHOD save.

    DATA: ls_scp1 TYPE ty_scp1,
          ls_text TYPE scprtext.

* copy everything to local, the function module changes the values
    ls_scp1 = is_scp1.

    READ TABLE ls_scp1-scprtext INTO ls_text WITH KEY langu = sy-langu.

    CALL FUNCTION 'SCPR_TEMPL_MN_TEMPLATE_SAVE'
      EXPORTING
        profid                    = ls_scp1-scprattr-id
        proftext                  = ls_text-text
        category                  = ls_scp1-scprattr-category
        cli_dep                   = ls_scp1-scprattr-cli_dep
        cli_cas                   = ls_scp1-scprattr-cli_cas
        reftype                   = ls_scp1-scprattr-reftype
        refname                   = ls_scp1-scprattr-refname
        orgid                     = ls_scp1-scprattr-orgid
        component                 = ls_scp1-scprattr-component
        minrelease                = ls_scp1-scprattr-minrelease
        maxrelease                = ls_scp1-scprattr-maxrelease
        act_info                  = ls_scp1-scprattr-act_info
        bcset_type                = ls_scp1-scprattr-type
        fldtxtvar_supplied        = 'YES'
        with_transp_insert        = abap_false
        with_progress_indicator   = abap_true
        remove_denied_data        = abap_true
        ask_for_cont_after_remove = abap_true
      TABLES
        values                    = ls_scp1-scprvals
        valuesl                   = ls_scp1-scprvall
        recattr                   = ls_scp1-scprreca
        it_fldv                   = ls_scp1-scprfldv
        texts                     = ls_scp1-scprtext
      EXCEPTIONS
        user_abort                = 1
        error_in_transport_layer  = 2
        inconsistent_data         = 3
        database_error            = 4
        OTHERS                    = 5.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |Error saving SCP1, { sy-tabix }| ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.

    SELECT SINGLE modifier INTO rv_user FROM scprattr
      WHERE id = ms_item-obj_name
      AND version = 'N'.
    IF sy-subrc <> 0 OR rv_user IS INITIAL.
      rv_user = c_user_unknown.
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~compare_to_remote_version.

    CREATE OBJECT ro_comparison_result TYPE zcl_abapgit_comparison_null.

  ENDMETHOD.

  METHOD zif_abapgit_object~delete.

    DATA: lv_id TYPE scpr_id.

    lv_id = ms_item-obj_name.

    enqueue( ).

* todo, this gives a popup
    CALL FUNCTION 'SCPR_CTRL_DELETE'
      EXPORTING
        profid             = lv_id
      EXCEPTIONS
        user_abort         = 1
        profile_dont_exist = 2.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |error while deleting SCP1, { sy-subrc }| ).
    ENDIF.

    dequeue( ).

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.

    DATA: ls_scp1 TYPE ty_scp1.

    io_xml->read(
      EXPORTING iv_name = 'SCP1'
      CHANGING  cg_data = ls_scp1 ).

    adjust_inbound( CHANGING cs_scp1 = ls_scp1 ).

    IF ls_scp1-scprattr-type = 'TMP'.
* todo, function module SCPR_PRSET_MN_BCSET_SAVE
      zcx_abapgit_exception=>raise( |todo, SCP1| ).
    ELSE.
      save( ls_scp1 ).
    ENDIF.

    dequeue( ).

    tadir_insert( iv_package ).

  ENDMETHOD.

  METHOD zif_abapgit_object~exists.

    DATA: lv_rc     TYPE sy-subrc,
          lv_profid TYPE scprattr-id.

    lv_profid = ms_item-obj_name.

    CALL FUNCTION 'SCPR_BCSET_EXISTS'
      EXPORTING
        profid = lv_profid
      IMPORTING
        rc     = lv_rc.
    rv_bool = boolc( lv_rc = 0 ).

  ENDMETHOD.

  METHOD zif_abapgit_object~get_metadata.

    rs_metadata = get_metadata( ).

  ENDMETHOD.

  METHOD zif_abapgit_object~has_changed_since.

    rv_changed = abap_true.

  ENDMETHOD.

  METHOD zif_abapgit_object~is_locked.

    rv_is_locked = abap_false.

  ENDMETHOD.

  METHOD zif_abapgit_object~jump.

    DATA: lv_display_only TYPE scpr_txt20,
          lv_bcset_id     TYPE scpr_id.

    lv_display_only = abap_false.
    lv_bcset_id     = ms_item-obj_name.

    EXPORT scpr3_display_only = lv_display_only
           scpr3_bcset_id     = lv_bcset_id
        TO MEMORY ID 'SCPR3_PARAMETER'.

    SUBMIT scpr3 AND RETURN.

  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.

    DATA: ls_scp1 TYPE ty_scp1.

    ls_scp1-scprattr-id = ms_item-obj_name.

    CALL FUNCTION 'SCPR_DB_ATTR_GET_DETAIL'
      EXPORTING
        profid     = ls_scp1-scprattr-id
      IMPORTING
        proftype   = ls_scp1-scprattr-type
        cli_dep    = ls_scp1-scprattr-cli_dep
        cli_cas    = ls_scp1-scprattr-cli_cas
        reftype    = ls_scp1-scprattr-reftype
        refname    = ls_scp1-scprattr-refname
        component  = ls_scp1-scprattr-component
        minrelease = ls_scp1-scprattr-minrelease
        maxrelease = ls_scp1-scprattr-maxrelease
        orgid      = ls_scp1-scprattr-orgid
        act_info   = ls_scp1-scprattr-act_info.

    IF ls_scp1-scprattr-type = 'TMP'.
* todo, Hierarchical, fm SCPR_PRSET_DB_SUBP_GET_DETAIL, recursive?
      zcx_abapgit_exception=>raise( |todo, SCP1| ).
    ELSE.
      load( CHANGING cs_scp1 = ls_scp1 ).
    ENDIF.

    adjust_outbound( CHANGING cs_scp1 = ls_scp1 ).

    io_xml->add(
      iv_name = 'SCP1'
      ig_data  = ls_scp1 ).

  ENDMETHOD.

  METHOD zif_abapgit_object~is_active.
    rv_active = is_active( ).
  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_object_scp1 DEFINITION
  PUBLIC
  INHERITING FROM zcl_abapgit_objects_super
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES zif_abapgit_object .
  PROTECTED SECTION.

    TYPES:
      BEGIN OF ty_scp1,
        scprattr TYPE scprattr,
        scprtext TYPE STANDARD TABLE OF scprtext WITH DEFAULT KEY,
        scprvals TYPE STANDARD TABLE OF scprvals WITH DEFAULT KEY,
        scprvall TYPE STANDARD TABLE OF scprvall WITH DEFAULT KEY,
        scprreca TYPE STANDARD TABLE OF scprreca WITH DEFAULT KEY,
        scprfldv TYPE STANDARD TABLE OF scprfldv WITH DEFAULT KEY,
      END OF ty_scp1 .

    METHODS dequeue .
    METHODS enqueue
      RAISING
        zcx_abapgit_exception .
    METHODS save
      IMPORTING
        !is_scp1 TYPE ty_scp1
      RAISING
        zcx_abapgit_exception .
    METHODS adjust_inbound
      CHANGING
        !cs_scp1 TYPE ty_scp1 .
    METHODS adjust_outbound
      CHANGING
        !cs_scp1 TYPE ty_scp1 .
    METHODS load
      CHANGING
        !cs_scp1 TYPE ty_scp1 .
    METHODS call_delete_fms
      IMPORTING i_profile_id TYPE scpr_id
      RAISING   zcx_abapgit_exception.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_abapgit_object_scp1 IMPLEMENTATION.

  METHOD adjust_inbound.

    FIELD-SYMBOLS: <ls_scprvals> TYPE scprvals,
                   <ls_scprreca> TYPE scprreca.

* back to internal format
    LOOP AT cs_scp1-scprvals ASSIGNING <ls_scprvals>.
      SHIFT <ls_scprvals>-recnumber RIGHT DELETING TRAILING space.
    ENDLOOP.
    LOOP AT cs_scp1-scprreca ASSIGNING <ls_scprreca>.
      SHIFT <ls_scprreca>-recnumber RIGHT DELETING TRAILING space.
    ENDLOOP.

  ENDMETHOD.

  METHOD adjust_outbound.

    FIELD-SYMBOLS: <ls_scprvals> TYPE scprvals,
                   <ls_scprreca> TYPE scprreca.

* normalize the XML
    LOOP AT cs_scp1-scprvals ASSIGNING <ls_scprvals>.
      CONDENSE <ls_scprvals>-recnumber.
    ENDLOOP.
    LOOP AT cs_scp1-scprreca ASSIGNING <ls_scprreca>.
      CONDENSE <ls_scprreca>-recnumber.
    ENDLOOP.

  ENDMETHOD.

  METHOD dequeue.

    DATA: lv_id TYPE scpr_id.

    lv_id = ms_item-obj_name.

    CALL FUNCTION 'SCPR_SV_DEQUEUE_BCSET'
      EXPORTING
        bcset_id = lv_id.

  ENDMETHOD.

  METHOD enqueue.

    DATA: lv_id TYPE scpr_id.

    lv_id = ms_item-obj_name.

    CALL FUNCTION 'SCPR_SV_ENQUEUE_BCSET'
      EXPORTING
        bcset_id          = lv_id
      EXCEPTIONS
        is_already_locked = 1
        system_failure    = 2
        OTHERS            = 3.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |SCP1 locking error| ).
    ENDIF.

  ENDMETHOD.

  METHOD load.

    CALL FUNCTION 'SCPR_TEXT_GET'
      EXPORTING
        profid        = cs_scp1-scprattr-id
        category      = cs_scp1-scprattr-category
      TABLES
        texts         = cs_scp1-scprtext
      EXCEPTIONS
        no_text_found = 1.

    CALL FUNCTION 'SCPR_TEMPL_DB_VALS_GET_DETAIL'
      EXPORTING
        profid   = cs_scp1-scprattr-id
        category = cs_scp1-scprattr-category
      TABLES
        values   = cs_scp1-scprvals
        valuesl  = cs_scp1-scprvall
        recattr  = cs_scp1-scprreca.

    CALL FUNCTION 'SCPR_TEMPL_DB_FLDTXTVAR_GET'
      EXPORTING
        bcset_id = cs_scp1-scprattr-id
        category = cs_scp1-scprattr-category
      TABLES
        it_fldv  = cs_scp1-scprfldv.

  ENDMETHOD.

  METHOD save.

    DATA: ls_scp1 TYPE ty_scp1,
          ls_text TYPE scprtext.

* copy everything to local, the function module changes the values
    ls_scp1 = is_scp1.

    READ TABLE ls_scp1-scprtext INTO ls_text WITH KEY langu = sy-langu.

    CALL FUNCTION 'SCPR_TEMPL_MN_TEMPLATE_SAVE'
      EXPORTING
        profid                    = ls_scp1-scprattr-id
        proftext                  = ls_text-text
        category                  = ls_scp1-scprattr-category
        cli_dep                   = ls_scp1-scprattr-cli_dep
        cli_cas                   = ls_scp1-scprattr-cli_cas
        reftype                   = ls_scp1-scprattr-reftype
        refname                   = ls_scp1-scprattr-refname
        orgid                     = ls_scp1-scprattr-orgid
        component                 = ls_scp1-scprattr-component
        minrelease                = ls_scp1-scprattr-minrelease
        maxrelease                = ls_scp1-scprattr-maxrelease
        act_info                  = ls_scp1-scprattr-act_info
        bcset_type                = ls_scp1-scprattr-type
        fldtxtvar_supplied        = 'YES'
        with_transp_insert        = abap_false
        with_progress_indicator   = abap_true
        remove_denied_data        = abap_true
        ask_for_cont_after_remove = abap_true
      TABLES
        values                    = ls_scp1-scprvals
        valuesl                   = ls_scp1-scprvall
        recattr                   = ls_scp1-scprreca
        it_fldv                   = ls_scp1-scprfldv
        texts                     = ls_scp1-scprtext
      EXCEPTIONS
        user_abort                = 1
        error_in_transport_layer  = 2
        inconsistent_data         = 3
        database_error            = 4
        OTHERS                    = 5.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |Error saving SCP1, { sy-tabix }| ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.

    SELECT SINGLE modifier INTO rv_user FROM scprattr
      WHERE id = ms_item-obj_name
      AND version = 'N'.
    IF sy-subrc <> 0 OR rv_user IS INITIAL.
      rv_user = c_user_unknown.
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~compare_to_remote_version.

    CREATE OBJECT ro_comparison_result TYPE zcl_abapgit_comparison_null.

  ENDMETHOD.

  METHOD zif_abapgit_object~delete.

    DATA: profile_id     TYPE scpr_id.
    profile_id = ms_item-obj_name.

    enqueue( ).
    call_delete_fms( profile_id ).
    dequeue( ).

  ENDMETHOD.

  METHOD call_delete_fms.

    CONSTANTS version_new      TYPE c VALUE 'N' ##NO_TEXT. "Include SCPRINTCONST version_new
    CONSTANTS operation_delete TYPE c VALUE 'D' ##NO_TEXT.
    DATA profile_type          TYPE scprattr-type.
    DATA fatherprofiles        TYPE standard table of scproprof WITH DEFAULT KEY.
    DATA fatherprofile         TYPE scproprof.

    CALL FUNCTION 'SCPR_DB_ATTR_GET_DETAIL'
      EXPORTING
        profid   = i_profile_id
        version  = version_new
      IMPORTING
        proftype = profile_type
      EXCEPTIONS
        OTHERS   = 0.

    CALL FUNCTION 'SCPR_PRSET_DB_USED_IN'
      EXPORTING
        profid   = i_profile_id
        version  = version_new
      TABLES
        profiles = fatherprofiles.

    fatherprofile-id       = i_profile_id.
    APPEND fatherprofile TO fatherprofiles.
    CALL FUNCTION 'SCPR_CT_TRANSPORT_ENTRIES'
      TABLES
        profids                  = fatherprofiles
      EXCEPTIONS
        error_in_transport_layer = 1
        user_abort               = 2.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |error while deleting SCP1 - TRANSPORT, { sy-subrc }| ).
    ENDIF.

    CALL FUNCTION 'SCPR_PRSET_DB_DELETE_ALL'
      EXPORTING
        profid      = i_profile_id
        proftype    = profile_type
      TABLES
        fatherprofs = fatherprofiles
      EXCEPTIONS
        user_abort  = 1.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |error while deleting SCP1 - DB_DELETE, { sy-subrc }| ).
    ENDIF.

    CALL FUNCTION 'SCPR_MEM_SCPR_ACTIONS_ADD'
      EXPORTING
        bcset_id  = i_profile_id
        operation = operation_delete.

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.

    DATA: ls_scp1 TYPE ty_scp1.

    io_xml->read(
      EXPORTING iv_name = 'SCP1'
      CHANGING  cg_data = ls_scp1 ).

    adjust_inbound( CHANGING cs_scp1 = ls_scp1 ).

    IF ls_scp1-scprattr-type = 'TMP'.
* todo, function module SCPR_PRSET_MN_BCSET_SAVE
      zcx_abapgit_exception=>raise( |todo, SCP1| ).
    ELSE.
      save( ls_scp1 ).
    ENDIF.

    dequeue( ).

    tadir_insert( iv_package ).

  ENDMETHOD.

  METHOD zif_abapgit_object~exists.

    DATA: lv_rc     TYPE sy-subrc,
          lv_profid TYPE scprattr-id.

    lv_profid = ms_item-obj_name.

    CALL FUNCTION 'SCPR_BCSET_EXISTS'
      EXPORTING
        profid = lv_profid
      IMPORTING
        rc     = lv_rc.
    rv_bool = boolc( lv_rc = 0 ).

  ENDMETHOD.

  METHOD zif_abapgit_object~get_metadata.

    rs_metadata = get_metadata( ).

  ENDMETHOD.

  METHOD zif_abapgit_object~has_changed_since.

    rv_changed = abap_true.

  ENDMETHOD.

  METHOD zif_abapgit_object~is_locked.

    rv_is_locked = abap_false.

  ENDMETHOD.

  METHOD zif_abapgit_object~jump.

    DATA: lv_display_only TYPE scpr_txt20,
          lv_bcset_id     TYPE scpr_id.

    lv_display_only = abap_false.
    lv_bcset_id     = ms_item-obj_name.

    EXPORT scpr3_display_only = lv_display_only
           scpr3_bcset_id     = lv_bcset_id
        TO MEMORY ID 'SCPR3_PARAMETER'.

    SUBMIT scpr3 AND RETURN.

  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.

    DATA: ls_scp1 TYPE ty_scp1.

    ls_scp1-scprattr-id = ms_item-obj_name.

    CALL FUNCTION 'SCPR_DB_ATTR_GET_DETAIL'
      EXPORTING
        profid     = ls_scp1-scprattr-id
      IMPORTING
        proftype   = ls_scp1-scprattr-type
        cli_dep    = ls_scp1-scprattr-cli_dep
        cli_cas    = ls_scp1-scprattr-cli_cas
        reftype    = ls_scp1-scprattr-reftype
        refname    = ls_scp1-scprattr-refname
        component  = ls_scp1-scprattr-component
        minrelease = ls_scp1-scprattr-minrelease
        maxrelease = ls_scp1-scprattr-maxrelease
        orgid      = ls_scp1-scprattr-orgid
        act_info   = ls_scp1-scprattr-act_info.

    IF ls_scp1-scprattr-type = 'TMP'.
* todo, Hierarchical, fm SCPR_PRSET_DB_SUBP_GET_DETAIL, recursive?
      zcx_abapgit_exception=>raise( |todo, SCP1| ).
    ELSE.
      load( CHANGING cs_scp1 = ls_scp1 ).
    ENDIF.

    adjust_outbound( CHANGING cs_scp1 = ls_scp1 ).

    io_xml->add(
      iv_name = 'SCP1'
      ig_data  = ls_scp1 ).

  ENDMETHOD.

  METHOD zif_abapgit_object~is_active.
    rv_active = is_active( ).
  ENDMETHOD.
ENDCLASS.

SCP1: delete in more direct way - no confirm popup

FM SCPR_PRSET_MN_DELETE has some confirmation popups so the delete is done in a more direct way without popups


*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_ENHS
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs DEFINITION INHERITING FROM lcl_objects_super FINAL.

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

ENDCLASS. "lcl_object_enhs

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs IMPLEMENTATION.

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

  METHOD lif_object~changed_by.

    DATA: lv_spot_name TYPE enhspotname,
          li_spot_ref  TYPE REF TO if_enh_spot_tool.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).
        li_spot_ref->get_attributes( IMPORTING changedby = rv_user ).
      CATCH cx_enh_root.
        rv_user = c_user_unknown.
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object~deserialize.

    DATA: lv_message          TYPE string,
          lv_parent           TYPE enhspotcompositename,
          lv_spot_name        TYPE enhspotname,
          lv_enh_shtext       TYPE string,
          ls_enh_badi         TYPE enh_badi_data,
          lt_enh_badi         TYPE enh_badi_data_it,
          lx_root             TYPE REF TO cx_root,
          lv_tool             TYPE enhspottooltype,
          lv_package          LIKE iv_package,
          li_spot_ref         TYPE REF TO if_enh_spot_tool,
          lo_badidef_tool     TYPE REF TO cl_enh_tool_badi_def,
          lo_hookdef_tool     TYPE REF TO cl_enh_tool_hook_def,
          lt_hook_definitions TYPE enh_hook_def_ext_it,
          li_enh_object       TYPE REF TO if_enh_object,
          li_enh_object_docu  TYPE REF TO if_enh_object_docu.

    lv_spot_name = ms_item-obj_name.

    io_xml->read( EXPORTING iv_name = 'TOOL'
                  CHANGING  cg_data = lv_tool ).
    io_xml->read( EXPORTING iv_name = 'SHORTTEXT'
                  CHANGING  cg_data = lv_enh_shtext ).

    IF lif_object~exists( ) = abap_true.
      lif_object~delete( ).
    ENDIF.

    lv_package = iv_package.

    TRY.
        cl_enh_factory=>create_enhancement_spot(
          EXPORTING
            spot_name      = lv_spot_name
            tooltype       = lv_tool
            dark           = abap_false
            compositename  = lv_parent
          IMPORTING
            spot           = li_spot_ref
          CHANGING
            devclass       = lv_package ).

        li_enh_object ?= li_spot_ref.
        li_enh_object_docu ?= li_spot_ref.

        li_enh_object_docu->set_shorttext( lv_enh_shtext ).

        CASE lv_tool.
          WHEN cl_enh_tool_badi_def=>tooltype.

            io_xml->read( EXPORTING iv_name = 'PARENT_COMP'
                          CHANGING  cg_data = lv_parent ).

            io_xml->read( EXPORTING iv_name = 'BADI_DATA'
                          CHANGING  cg_data = lt_enh_badi ).

            lo_badidef_tool ?= li_spot_ref.

            LOOP AT lt_enh_badi INTO ls_enh_badi.
              lo_badidef_tool->add_badi_def( ls_enh_badi ).
            ENDLOOP.

          WHEN cl_enh_tool_hook_def=>tool_type.

            io_xml->read( EXPORTING iv_name = 'BADI_DATA'
                          CHANGING  cg_data = lt_hook_definitions ).

            lo_hookdef_tool ?= li_spot_ref.

            LOOP AT lt_hook_definitions ASSIGNING FIELD-SYMBOL(<ls_hook_def>).
              lo_hookdef_tool->add_hook_def( CORRESPONDING #( <ls_hook_def> ) ).
            ENDLOOP.

        ENDCASE.

        li_enh_object->save( ).
        li_enh_object->activate( ).
        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_root.
        lv_message = `Error occured while deserializing EHNS: `
          && lx_root->get_text( ) ##NO_TEXT.
        zcx_abapgit_exception=>raise( lv_message ).
    ENDTRY.

  ENDMETHOD.  "deserialize

  METHOD lif_object~serialize.

    DATA: lv_spot_name        TYPE enhspotname,
          lv_enh_shtext       TYPE string,
          lv_parent           TYPE enhspotcompositename,
          lt_enh_badi         TYPE enh_badi_data_it,
          lv_tool             TYPE enhspottooltype,
          lx_root             TYPE REF TO cx_root,
          li_spot_ref         TYPE REF TO if_enh_spot_tool,
          lo_badidef_tool     TYPE REF TO cl_enh_tool_badi_def,
          lo_hookdef_tool     TYPE REF TO cl_enh_tool_hook_def,
          lt_hook_definitions TYPE enh_hook_def_ext_it,
          li_enh_object_docu  TYPE REF TO if_enh_object_docu.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).
        lv_tool = li_spot_ref->get_tool( ).

        li_enh_object_docu ?= li_spot_ref.
        lv_enh_shtext = li_enh_object_docu->get_shorttext( ).

        io_xml->add( ig_data = lv_tool
                     iv_name = 'TOOL' ).
        io_xml->add( ig_data = lv_enh_shtext
                     iv_name = 'SHORTTEXT' ).

        CASE lv_tool.
          WHEN cl_enh_tool_badi_def=>tooltype.

            lo_badidef_tool ?= li_spot_ref.

            "get parent = composite enhs (ENHC)
            lv_parent = cl_r3standard_persistence=>enh_find_parent_composite( lv_spot_name ).
            "get subsequent BADI definitions
            lt_enh_badi = lo_badidef_tool->get_badi_defs( ).

            io_xml->add( ig_data = lv_parent
                         iv_name = 'PARENT_COMP' ).
            io_xml->add( ig_data = lt_enh_badi
                         iv_name = 'BADI_DATA' ).

          WHEN cl_enh_tool_hook_def=>tool_type.

            lo_hookdef_tool ?= li_spot_ref.

            lt_hook_definitions = lo_hookdef_tool->get_hook_defs( ).

            io_xml->add( ig_data = lt_hook_definitions
                         iv_name = 'BADI_DATA' ).

          WHEN OTHERS.
            zcx_abapgit_exception=>raise( |ENHS: Unsupported tool { lv_tool }| ).
        ENDCASE.

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( `Error occured while serializing EHNS: `
          && lx_root->get_text( ) ) ##NO_TEXT.
    ENDTRY.

  ENDMETHOD.  "serialize

  METHOD lif_object~exists.

    DATA: lv_spot_name TYPE enhspotname,
          lv_tool      TYPE enhspottooltype,
          li_spot_ref  TYPE REF TO if_enh_spot_tool.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).

        lv_tool = li_spot_ref->get_tool( ).

        rv_bool = abap_true.

      CATCH cx_enh_root.
        rv_bool = abap_false.
    ENDTRY.

  ENDMETHOD.  "exists

  METHOD lif_object~delete.

    DATA: lv_spot_name  TYPE enhspotname,
          lx_root       TYPE REF TO cx_root,
          li_enh_object TYPE REF TO if_enh_object.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_enh_object ?= cl_enh_factory=>get_enhancement_spot(
                            spot_name = lv_spot_name
                            lock      = abap_true ).

        li_enh_object->delete( nevertheless_delete = abap_true
                               run_dark            = abap_true ).

        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( `Error occured while deleting EHNS: `
          && lx_root->get_text( ) ) ##NO_TEXT.
    ENDTRY.

  ENDMETHOD.  "delete

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.  "get_metadata

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation     = 'SHOW'
        object_name   = ms_item-obj_name
        object_type   = 'ENHS'
        in_new_window = abap_true.

  ENDMETHOD.  "jump

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

ENDCLASS. "lcl_object_enhs

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_ENHS
*&---------------------------------------------------------------------*

* For complete list of tool_type - see ENHSPOTTOOLS table

INTERFACE lif_object_enhs.

  METHODS:
    deserialize
      IMPORTING io_xml           TYPE REF TO lcl_xml_input
                iv_package       TYPE devclass
                ii_enh_spot_tool TYPE REF TO if_enh_spot_tool
      RAISING   zcx_abapgit_exception,

    serialize
      IMPORTING io_xml           TYPE REF TO lcl_xml_output
                ii_enh_spot_tool TYPE REF TO if_enh_spot_tool
      RAISING   zcx_abapgit_exception.

ENDINTERFACE.                    "lif_object_enho

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs DEFINITION INHERITING FROM lcl_objects_super FINAL.

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

  PRIVATE SECTION.
    METHODS:
      factory
        IMPORTING
          iv_tool        TYPE enhtooltype
        RETURNING
          VALUE(ri_enho) TYPE REF TO lif_object_enhs
        RAISING
          zcx_abapgit_exception.

ENDCLASS. "lcl_object_enhs

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_badi_def DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_badi_def DEFINITION.

  PUBLIC SECTION.
    INTERFACES: lif_object_enhs.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_hook_def DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_hook_def DEFINITION.

  PUBLIC SECTION.
    INTERFACES: lif_object_enhs.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs IMPLEMENTATION.

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

  METHOD lif_object~changed_by.

    DATA: lv_spot_name TYPE enhspotname,
          li_spot_ref  TYPE REF TO if_enh_spot_tool.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).
        li_spot_ref->get_attributes( IMPORTING changedby = rv_user ).
      CATCH cx_enh_root.
        rv_user = c_user_unknown.
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object~deserialize.

    DATA: lv_parent    TYPE enhspotcompositename,
          lv_spot_name TYPE enhspotname,
          lx_root      TYPE REF TO cx_root,
          lv_tool      TYPE enhspottooltype,
          lv_package   LIKE iv_package,
          li_spot_ref  TYPE REF TO if_enh_spot_tool,
          li_enhs      TYPE REF TO lif_object_enhs.

    lv_spot_name = ms_item-obj_name.

    io_xml->read( EXPORTING iv_name = 'TOOL'
                  CHANGING  cg_data = lv_tool ).

    IF lif_object~exists( ) = abap_true.
      lif_object~delete( ).
    ENDIF.

    lv_package = iv_package.

    TRY.
        cl_enh_factory=>create_enhancement_spot(
          EXPORTING
            spot_name      = lv_spot_name
            tooltype       = lv_tool
            dark           = abap_false
            compositename  = lv_parent
          IMPORTING
            spot           = li_spot_ref
          CHANGING
            devclass       = lv_package ).

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( 'Error from CL_ENH_FACTORY' ).
    ENDTRY.

    li_enhs = factory( lv_tool ).

    li_enhs->deserialize( io_xml           = io_xml
                          iv_package       = iv_package
                          ii_enh_spot_tool = li_spot_ref ).

  ENDMETHOD.  "deserialize

  METHOD lif_object~serialize.

    DATA: lv_spot_name TYPE enhspotname,
          lx_root      TYPE REF TO cx_root,
          li_spot_ref  TYPE REF TO if_enh_spot_tool,
          li_enhs      TYPE REF TO lif_object_enhs.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( 'Error from CL_ENH_FACTORY' ).
    ENDTRY.

    li_enhs = factory( li_spot_ref->get_tool( ) ).

    li_enhs->serialize( io_xml           = io_xml
                        ii_enh_spot_tool = li_spot_ref ).

  ENDMETHOD.  "serialize

  METHOD lif_object~exists.

    DATA: lv_spot_name TYPE enhspotname,
          lv_tool      TYPE enhspottooltype,
          li_spot_ref  TYPE REF TO if_enh_spot_tool.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).

        lv_tool = li_spot_ref->get_tool( ).

        rv_bool = abap_true.

      CATCH cx_enh_root.
        rv_bool = abap_false.
    ENDTRY.

  ENDMETHOD.  "exists

  METHOD lif_object~delete.

    DATA: lv_spot_name  TYPE enhspotname,
          lx_root       TYPE REF TO cx_root,
          li_enh_object TYPE REF TO if_enh_object.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_enh_object ?= cl_enh_factory=>get_enhancement_spot(
                            spot_name = lv_spot_name
                            lock      = abap_true ).

        li_enh_object->delete( nevertheless_delete = abap_true
                               run_dark            = abap_true ).

        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( `Error occured while deleting EHNS: `
          && lx_root->get_text( ) ) ##NO_TEXT.
    ENDTRY.

  ENDMETHOD.  "delete

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.  "get_metadata

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation     = 'SHOW'
        object_name   = ms_item-obj_name
        object_type   = 'ENHS'
        in_new_window = abap_true.

  ENDMETHOD.  "jump

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

  METHOD factory.

    CASE iv_tool.
      WHEN cl_enh_tool_badi_def=>tooltype.
        CREATE OBJECT ri_enho TYPE lcl_object_enhs_badi_def.
      WHEN cl_enh_tool_hook_def=>tool_type.
        CREATE OBJECT ri_enho TYPE lcl_object_enhs_hook_def.
      WHEN OTHERS.
        zcx_abapgit_exception=>raise( |ENHS: Unsupported tool { iv_tool }| ).
    ENDCASE.

  ENDMETHOD.

ENDCLASS. "lcl_object_enhs

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_badi_def IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_badi_def IMPLEMENTATION.

  METHOD lif_object_enhs~deserialize.

    DATA: lv_parent          TYPE enhspotcompositename,
          ls_enh_badi        TYPE enh_badi_data,
          lt_enh_badi        TYPE enh_badi_data_it,
          lo_badidef_tool    TYPE REF TO cl_enh_tool_badi_def,
          lv_enh_shtext      TYPE string,
          lv_package         LIKE iv_package,
          li_enh_object      TYPE REF TO if_enh_object,
          li_enh_object_docu TYPE REF TO if_enh_object_docu,
          lx_error           TYPE REF TO cx_enh_root,
          lv_text            TYPE string.

    io_xml->read( EXPORTING iv_name = 'PARENT_COMP'
                  CHANGING  cg_data = lv_parent ).

    io_xml->read( EXPORTING iv_name = 'BADI_DATA'
                  CHANGING  cg_data = lt_enh_badi ).

    io_xml->read( EXPORTING iv_name = 'SHORTTEXT'
                  CHANGING  cg_data = lv_enh_shtext ).

    lv_package = iv_package.

    li_enh_object ?= ii_enh_spot_tool.
    li_enh_object_docu ?= ii_enh_spot_tool.

    TRY.
        li_enh_object_docu->set_shorttext( lv_enh_shtext ).

        lo_badidef_tool ?= ii_enh_spot_tool.

        LOOP AT lt_enh_badi INTO ls_enh_badi.
          lo_badidef_tool->add_badi_def( ls_enh_badi ).
        ENDLOOP.

        li_enh_object->save( ).
        li_enh_object->activate( ).
        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_error.
        lv_text = lx_error->get_text( ).
        zcx_abapgit_exception=>raise( lv_text ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object_enhs~serialize.

    DATA: lv_spot_name       TYPE enhspotname,
          lv_parent          TYPE enhspotcompositename,
          lt_enh_badi        TYPE enh_badi_data_it,
          lo_badidef_tool    TYPE REF TO cl_enh_tool_badi_def,
          lv_enh_shtext      TYPE string,
          li_enh_object_docu TYPE REF TO if_enh_object_docu.

    lo_badidef_tool ?= ii_enh_spot_tool.

    li_enh_object_docu ?= ii_enh_spot_tool.
    lv_enh_shtext = li_enh_object_docu->get_shorttext( ).

    "get parent = composite enhs (ENHC)
    lv_parent = cl_r3standard_persistence=>enh_find_parent_composite( lv_spot_name ).
    "get subsequent BADI definitions
    lt_enh_badi = lo_badidef_tool->get_badi_defs( ).

    io_xml->add( ig_data = ii_enh_spot_tool->get_tool( )
                 iv_name = 'TOOL' ).

    io_xml->add( ig_data = lv_enh_shtext
                 iv_name = 'SHORTTEXT' ).

    io_xml->add( ig_data = lv_parent
                 iv_name = 'PARENT_COMP' ).

    io_xml->add( ig_data = lt_enh_badi
                 iv_name = 'BADI_DATA' ).

  ENDMETHOD.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_hook_def IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_hook_def IMPLEMENTATION.

  METHOD lif_object_enhs~deserialize.

    DATA: lv_enh_shtext       TYPE string,
          ls_hook_def         TYPE enh_hook_def,
          li_enh_object       TYPE REF TO if_enh_object,
          li_enh_object_docu  TYPE REF TO if_enh_object_docu,
          lo_hookdef_tool     TYPE REF TO cl_enh_tool_hook_def,
          lt_hook_definitions TYPE enh_hook_def_ext_it,
          lx_error            TYPE REF TO cx_enh_root,
          lv_text             TYPE string.

    io_xml->read( EXPORTING iv_name = 'SHORTTEXT'
                  CHANGING  cg_data = lv_enh_shtext ).

    io_xml->read( EXPORTING iv_name = 'BADI_DATA'
                  CHANGING  cg_data = lt_hook_definitions ).

    li_enh_object ?= ii_enh_spot_tool.
    li_enh_object_docu ?= ii_enh_spot_tool.

    TRY.
        li_enh_object_docu->set_shorttext( lv_enh_shtext ).

        lo_hookdef_tool ?= ii_enh_spot_tool.

        LOOP AT lt_hook_definitions ASSIGNING FIELD-SYMBOL(<ls_hook_def>).
          MOVE-CORRESPONDING <ls_hook_def> TO ls_hook_def.
          lo_hookdef_tool->add_hook_def( ls_hook_def ).
        ENDLOOP.

        li_enh_object->save( ).
        li_enh_object->activate( ).
        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_error.
        lv_text = lx_error->get_text( ).
        zcx_abapgit_exception=>raise( lv_text ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object_enhs~serialize.

    DATA: lo_hookdef_tool     TYPE REF TO cl_enh_tool_hook_def,
          lt_hook_definitions TYPE enh_hook_def_ext_it,
          lv_enh_shtext       TYPE string,
          li_enh_object_docu  TYPE REF TO if_enh_object_docu.

    lo_hookdef_tool ?= ii_enh_spot_tool.

    li_enh_object_docu ?= ii_enh_spot_tool.
    lv_enh_shtext = li_enh_object_docu->get_shorttext( ).

    lt_hook_definitions = lo_hookdef_tool->get_hook_defs( ).

    io_xml->add( ig_data = ii_enh_spot_tool->get_tool( )
                 iv_name = 'TOOL' ).

    io_xml->add( ig_data = lv_enh_shtext
                 iv_name = 'SHORTTEXT' ).

    io_xml->add( ig_data = lt_hook_definitions
                 iv_name = 'BADI_DATA' ).

  ENDMETHOD.

ENDCLASS.

Refactor to strategy pattern

Refactor to strategy pattern


CLASS zcl_abapgit_object_ssfo DEFINITION PUBLIC INHERITING FROM zcl_abapgit_objects_super FINAL.

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

  PRIVATE SECTION.
    METHODS: fix_ids IMPORTING ii_xml_doc TYPE REF TO if_ixml_document.

ENDCLASS.

CLASS zcl_abapgit_object_ssfo IMPLEMENTATION.

  METHOD zif_abapgit_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.

    SELECT SINGLE lastuser FROM stxfadm INTO rv_user
      WHERE formname = ms_item-obj_name.
    IF sy-subrc <> 0.
      rv_user = c_user_unknown.
    ENDIF.

  ENDMETHOD.

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

  METHOD zif_abapgit_object~exists.

    DATA: lv_formname TYPE stxfadm-formname.

    SELECT SINGLE formname FROM stxfadm INTO lv_formname
      WHERE formname = ms_item-obj_name.
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD zif_abapgit_object~jump.

    DATA: lt_bdcdata TYPE TABLE OF bdcdata.

    FIELD-SYMBOLS: <ls_bdcdata> LIKE LINE OF lt_bdcdata.

    APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
    <ls_bdcdata>-program  = 'SAPMSSFO'.
    <ls_bdcdata>-dynpro   = '0100'.
    <ls_bdcdata>-dynbegin = abap_true.

    APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
    <ls_bdcdata>-fnam = 'BDC_OKCODE'.
    <ls_bdcdata>-fval = '=DISPLAY'.

    APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
    <ls_bdcdata>-fnam = 'RB_SF'.
    <ls_bdcdata>-fval = abap_true.

    APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
    <ls_bdcdata>-fnam = 'SSFSCREEN-FNAME'.
    <ls_bdcdata>-fval = ms_item-obj_name.

    CALL FUNCTION 'ABAP4_CALL_TRANSACTION'
      STARTING NEW TASK 'GIT'
      EXPORTING
        tcode                 = 'SMARTFORMS'
        mode_val              = 'E'
      TABLES
        using_tab             = lt_bdcdata
      EXCEPTIONS
        system_failure        = 1
        communication_failure = 2
        resource_failure      = 3
        OTHERS                = 4
        ##fm_subrc_ok.                                                   "#EC CI_SUBRC

  ENDMETHOD.

  METHOD zif_abapgit_object~delete.

    DATA: lv_formname TYPE tdsfname.

    lv_formname = ms_item-obj_name.

    CALL FUNCTION 'FB_DELETE_FORM'
      EXPORTING
        i_formname            = lv_formname
        i_with_dialog         = abap_false
        i_with_confirm_dialog = abap_false
      EXCEPTIONS
        no_name               = 1
        no_form               = 2
        form_locked           = 3
        no_access_permission  = 4
        illegal_language      = 5
        illegal_formtype      = 6
        OTHERS                = 7.
    IF sy-subrc <> 0 AND sy-subrc <> 2.
      zcx_abapgit_exception=>raise( 'Error from FB_DELETE_FORM' ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.
* see function module FB_DOWNLOAD_FORM

    DATA: lo_sf       TYPE REF TO cl_ssf_fb_smart_form,
          lv_name     TYPE string,
          li_node     TYPE REF TO if_ixml_node,
          li_element  TYPE REF TO if_ixml_element,
          li_iterator TYPE REF TO if_ixml_node_iterator,
          lv_formname TYPE tdsfname,
          li_ixml     TYPE REF TO if_ixml,
          li_xml_doc  TYPE REF TO if_ixml_document.

    li_ixml = cl_ixml=>create( ).
    li_xml_doc = li_ixml->create_document( ).

    CREATE OBJECT lo_sf.
    lv_formname = ms_item-obj_name. " convert type
    TRY.
        lo_sf->load( im_formname = lv_formname
                     im_language = '' ).
      CATCH cx_ssf_fb.
* the smartform is not present in system, or other error occured
        RETURN.
    ENDTRY.

    lo_sf->xml_download( EXPORTING parent   = li_xml_doc
                         CHANGING  document = li_xml_doc ).

    li_iterator = li_xml_doc->create_iterator( ).
    li_node = li_iterator->get_next( ).
    WHILE NOT li_node IS INITIAL.

      lv_name = li_node->get_name( ).
      IF lv_name = 'DEVCLASS'
          OR lv_name = 'LASTDATE'
          OR lv_name = 'LASTTIME'.
        li_node->set_value( '' ).
      ENDIF.
      IF lv_name = 'FIRSTUSER'
          OR lv_name = 'LASTUSER'.
        li_node->set_value( 'DUMMY' ).
      ENDIF.

      li_node = li_iterator->get_next( ).
    ENDWHILE.

    fix_ids( li_xml_doc ).

    li_element = li_xml_doc->get_root_element( ).
    li_element->set_attribute(
      name      = 'sf'
      namespace = 'xmlns'
      value     = 'urn:sap-com:SmartForms:2000:internal-structure' ). "#EC NOTEXT
    li_element->set_attribute(
      name  = 'xmlns'
      value = 'urn:sap-com:sdixml-ifr:2000' ).              "#EC NOTEXT

    io_xml->set_raw( li_xml_doc->get_root_element( ) ).

  ENDMETHOD.

  METHOD fix_ids.
* makes sure ID and IDREF values are the same values for each serialization run
* the standard code has a counter that keeps increasing values

    DATA: lv_name     TYPE string,
          li_idref    TYPE REF TO if_ixml_node,
          li_node     TYPE REF TO if_ixml_node,
          li_attr     TYPE REF TO if_ixml_named_node_map,
          li_iterator TYPE REF TO if_ixml_node_iterator,
          lt_idref    TYPE STANDARD TABLE OF string WITH DEFAULT KEY.

    li_iterator = ii_xml_doc->create_iterator( ).
    li_node = li_iterator->get_next( ).
    WHILE NOT li_node IS INITIAL.
      lv_name = li_node->get_name( ).
      IF lv_name = 'NODE' OR lv_name = 'WINDOW'.
        li_idref = li_node->get_attributes( )->get_named_item( 'IDREF' ).
        IF li_idref IS BOUND.
          APPEND li_idref->get_value( ) TO lt_idref.
          li_idref->set_value( |{ sy-tabix }| ).
        ENDIF.
      ENDIF.
      li_node = li_iterator->get_next( ).
    ENDWHILE.

    li_iterator = ii_xml_doc->create_iterator( ).
    li_node = li_iterator->get_next( ).
    WHILE NOT li_node IS INITIAL.
      lv_name = li_node->get_name( ).
      IF lv_name = 'NODE' OR lv_name = 'WINDOW'.
        li_idref = li_node->get_attributes( )->get_named_item( 'ID' ).
        IF li_idref IS BOUND.
          lv_name = li_idref->get_value( ).
          READ TABLE lt_idref WITH KEY table_line = lv_name TRANSPORTING NO FIELDS.
          IF sy-subrc = 0.
            li_idref->set_value( |{ sy-tabix }| ).
          ELSE.
            li_attr = li_node->get_attributes( ).
            li_attr->remove_named_item( 'ID' ).
          ENDIF.
        ENDIF.
      ENDIF.
      li_node = li_iterator->get_next( ).
    ENDWHILE.

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.
* see function module FB_UPLOAD_FORM

    DATA: li_node     TYPE REF TO if_ixml_node,
          lv_formname TYPE tdsfname,
          lv_name     TYPE string,
          li_iterator TYPE REF TO if_ixml_node_iterator,
          lo_sf       TYPE REF TO cl_ssf_fb_smart_form,
          lo_res      TYPE REF TO cl_ssf_fb_smart_form,
          lx_error    TYPE REF TO cx_ssf_fb,
          lv_text     TYPE string.

    CREATE OBJECT lo_sf.

* set "created by" and "changed by" to current user
    li_iterator = io_xml->get_raw( )->get_root_element( )->create_iterator( ).
    li_node = li_iterator->get_next( ).
    WHILE NOT li_node IS INITIAL.
      lv_name = li_node->get_name( ).
      CASE lv_name.
        WHEN 'LASTDATE'.
          li_node->set_value(
            sy-datum(4) && '-' && sy-datum+4(2) && '-' && sy-datum+6(2) ).
        WHEN 'LASTTIME'.
          li_node->set_value(
            sy-uzeit(2) && ':' && sy-uzeit+2(2) && ':' && sy-uzeit+4(2) ).
        WHEN 'FIRSTUSER' OR 'LASTUSER'.
          li_node->set_value( sy-uname && '' ).
      ENDCASE.

      li_node = li_iterator->get_next( ).
    ENDWHILE.

    tadir_insert( iv_package ).

    lv_formname = ms_item-obj_name.

    TRY.
        lo_sf->enqueue( suppress_corr_check = space
                        master_language     = mv_language
                        mode                = 'INSERT'
                        formname            = lv_formname ).

        lo_sf->xml_upload( EXPORTING dom      = io_xml->get_raw( )->get_root_element( )
                                     formname = lv_formname
                                     language = mv_language
                           CHANGING  sform    = lo_res ).

        lo_res->store( im_formname = lo_res->header-formname
                       im_language = mv_language
                       im_active   = abap_true ).

        lo_sf->dequeue( lv_formname ).

      CATCH cx_ssf_fb INTO lx_error.
        lv_text = lx_error->get_text( ).
        zcx_abapgit_exception=>raise( |{ ms_item-obj_type } { ms_item-obj_name }: { lv_text } | ).
    ENDTRY.

  ENDMETHOD.

  METHOD zif_abapgit_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE zcl_abapgit_comparison_null.
  ENDMETHOD.

  METHOD zif_abapgit_object~is_locked.

    rv_is_locked = exists_a_lock_entry_for( iv_lock_object = 'E_SMFORM'
                                            iv_argument    = |{ ms_item-obj_name }| ).

  ENDMETHOD.

ENDCLASS.

CLASS zcl_abapgit_object_ssfo DEFINITION PUBLIC INHERITING FROM zcl_abapgit_objects_super FINAL.

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

  PRIVATE SECTION.
    METHODS: fix_ids IMPORTING ii_xml_doc TYPE REF TO if_ixml_document.

ENDCLASS.

CLASS zcl_abapgit_object_ssfo IMPLEMENTATION.

  METHOD zif_abapgit_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.

    SELECT SINGLE lastuser FROM stxfadm INTO rv_user
      WHERE formname = ms_item-obj_name.
    IF sy-subrc <> 0.
      rv_user = c_user_unknown.
    ENDIF.

  ENDMETHOD.

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

  METHOD zif_abapgit_object~exists.

    DATA: lv_formname TYPE stxfadm-formname.

    SELECT SINGLE formname FROM stxfadm INTO lv_formname
      WHERE formname = ms_item-obj_name.
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD zif_abapgit_object~jump.

    DATA: lt_bdcdata  TYPE TABLE OF bdcdata,
          lv_formtype TYPE stxfadm-formtype.

    FIELD-SYMBOLS: <ls_bdcdata> LIKE LINE OF lt_bdcdata.

    APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
    <ls_bdcdata>-program  = 'SAPMSSFO'.
    <ls_bdcdata>-dynpro   = '0100'.
    <ls_bdcdata>-dynbegin = abap_true.

    SELECT SINGLE formtype FROM stxfadm INTO lv_formtype
           WHERE formname = ms_item-obj_name.

    IF lv_formtype = cssf_formtype_text.

      APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
      <ls_bdcdata>-fnam = 'RB_TX'.
      <ls_bdcdata>-fval = abap_true.

      APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
      <ls_bdcdata>-fnam = 'BDC_OKCODE'.
      <ls_bdcdata>-fval = '=RB'.

      APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
      <ls_bdcdata>-program  = 'SAPMSSFO'.
      <ls_bdcdata>-dynpro   = '0100'.
      <ls_bdcdata>-dynbegin = abap_true.

      APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
      <ls_bdcdata>-fnam = 'SSFSCREEN-TNAME'.
      <ls_bdcdata>-fval = ms_item-obj_name.

    ELSE.

      APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
      <ls_bdcdata>-fnam = 'SSFSCREEN-FNAME'.
      <ls_bdcdata>-fval = ms_item-obj_name.

    ENDIF.

    APPEND INITIAL LINE TO lt_bdcdata ASSIGNING <ls_bdcdata>.
    <ls_bdcdata>-fnam = 'BDC_OKCODE'.
    <ls_bdcdata>-fval = '=DISPLAY'.

    CALL FUNCTION 'ABAP4_CALL_TRANSACTION'
      STARTING NEW TASK 'GIT'
      EXPORTING
        tcode                 = 'SMARTFORMS'
        mode_val              = 'E'
      TABLES
        using_tab             = lt_bdcdata
      EXCEPTIONS
        system_failure        = 1
        communication_failure = 2
        resource_failure      = 3
        OTHERS                = 4
        ##fm_subrc_ok.                                                   "#EC CI_SUBRC

  ENDMETHOD.

  METHOD zif_abapgit_object~delete.

    DATA: lv_formname TYPE tdsfname.

    lv_formname = ms_item-obj_name.

    CALL FUNCTION 'FB_DELETE_FORM'
      EXPORTING
        i_formname            = lv_formname
        i_with_dialog         = abap_false
        i_with_confirm_dialog = abap_false
      EXCEPTIONS
        no_name               = 1
        no_form               = 2
        form_locked           = 3
        no_access_permission  = 4
        illegal_language      = 5
        illegal_formtype      = 6
        OTHERS                = 7.
    IF sy-subrc <> 0 AND sy-subrc <> 2.
      zcx_abapgit_exception=>raise( 'Error from FB_DELETE_FORM' ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.
* see function module FB_DOWNLOAD_FORM

    DATA: lo_sf       TYPE REF TO cl_ssf_fb_smart_form,
          lv_name     TYPE string,
          li_node     TYPE REF TO if_ixml_node,
          li_element  TYPE REF TO if_ixml_element,
          li_iterator TYPE REF TO if_ixml_node_iterator,
          lv_formname TYPE tdsfname,
          li_ixml     TYPE REF TO if_ixml,
          li_xml_doc  TYPE REF TO if_ixml_document.

    li_ixml = cl_ixml=>create( ).
    li_xml_doc = li_ixml->create_document( ).

    CREATE OBJECT lo_sf.
    lv_formname = ms_item-obj_name. " convert type
    TRY.
        lo_sf->load( im_formname = lv_formname
                     im_language = '' ).
      CATCH cx_ssf_fb.
* the smartform is not present in system, or other error occured
        RETURN.
    ENDTRY.

    lo_sf->xml_download( EXPORTING parent   = li_xml_doc
                         CHANGING  document = li_xml_doc ).

    li_iterator = li_xml_doc->create_iterator( ).
    li_node = li_iterator->get_next( ).
    WHILE NOT li_node IS INITIAL.

      lv_name = li_node->get_name( ).
      IF lv_name = 'DEVCLASS'
          OR lv_name = 'LASTDATE'
          OR lv_name = 'LASTTIME'.
        li_node->set_value( '' ).
      ENDIF.
      IF lv_name = 'FIRSTUSER'
          OR lv_name = 'LASTUSER'.
        li_node->set_value( 'DUMMY' ).
      ENDIF.

      li_node = li_iterator->get_next( ).
    ENDWHILE.

    fix_ids( li_xml_doc ).

    li_element = li_xml_doc->get_root_element( ).
    li_element->set_attribute(
      name      = 'sf'
      namespace = 'xmlns'
      value     = 'urn:sap-com:SmartForms:2000:internal-structure' ). "#EC NOTEXT
    li_element->set_attribute(
      name  = 'xmlns'
      value = 'urn:sap-com:sdixml-ifr:2000' ).              "#EC NOTEXT

    io_xml->set_raw( li_xml_doc->get_root_element( ) ).

  ENDMETHOD.

  METHOD fix_ids.
* makes sure ID and IDREF values are the same values for each serialization run
* the standard code has a counter that keeps increasing values

    DATA: lv_name     TYPE string,
          li_idref    TYPE REF TO if_ixml_node,
          li_node     TYPE REF TO if_ixml_node,
          li_attr     TYPE REF TO if_ixml_named_node_map,
          li_iterator TYPE REF TO if_ixml_node_iterator,
          lt_idref    TYPE STANDARD TABLE OF string WITH DEFAULT KEY.

    li_iterator = ii_xml_doc->create_iterator( ).
    li_node = li_iterator->get_next( ).
    WHILE NOT li_node IS INITIAL.
      lv_name = li_node->get_name( ).
      IF lv_name = 'NODE' OR lv_name = 'WINDOW'.
        li_idref = li_node->get_attributes( )->get_named_item( 'IDREF' ).
        IF li_idref IS BOUND.
          APPEND li_idref->get_value( ) TO lt_idref.
          li_idref->set_value( |{ sy-tabix }| ).
        ENDIF.
      ENDIF.
      li_node = li_iterator->get_next( ).
    ENDWHILE.

    li_iterator = ii_xml_doc->create_iterator( ).
    li_node = li_iterator->get_next( ).
    WHILE NOT li_node IS INITIAL.
      lv_name = li_node->get_name( ).
      IF lv_name = 'NODE' OR lv_name = 'WINDOW'.
        li_idref = li_node->get_attributes( )->get_named_item( 'ID' ).
        IF li_idref IS BOUND.
          lv_name = li_idref->get_value( ).
          READ TABLE lt_idref WITH KEY table_line = lv_name TRANSPORTING NO FIELDS.
          IF sy-subrc = 0.
            li_idref->set_value( |{ sy-tabix }| ).
          ELSE.
            li_attr = li_node->get_attributes( ).
            li_attr->remove_named_item( 'ID' ).
          ENDIF.
        ENDIF.
      ENDIF.
      li_node = li_iterator->get_next( ).
    ENDWHILE.

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.
* see function module FB_UPLOAD_FORM

    DATA: li_node     TYPE REF TO if_ixml_node,
          lv_formname TYPE tdsfname,
          lv_name     TYPE string,
          li_iterator TYPE REF TO if_ixml_node_iterator,
          lo_sf       TYPE REF TO cl_ssf_fb_smart_form,
          lo_res      TYPE REF TO cl_ssf_fb_smart_form,
          lx_error    TYPE REF TO cx_ssf_fb,
          lv_text     TYPE string.

    CREATE OBJECT lo_sf.

* set "created by" and "changed by" to current user
    li_iterator = io_xml->get_raw( )->get_root_element( )->create_iterator( ).
    li_node = li_iterator->get_next( ).
    WHILE NOT li_node IS INITIAL.
      lv_name = li_node->get_name( ).
      CASE lv_name.
        WHEN 'LASTDATE'.
          li_node->set_value(
            sy-datum(4) && '-' && sy-datum+4(2) && '-' && sy-datum+6(2) ).
        WHEN 'LASTTIME'.
          li_node->set_value(
            sy-uzeit(2) && ':' && sy-uzeit+2(2) && ':' && sy-uzeit+4(2) ).
        WHEN 'FIRSTUSER' OR 'LASTUSER'.
          li_node->set_value( sy-uname && '' ).
      ENDCASE.

      li_node = li_iterator->get_next( ).
    ENDWHILE.

    tadir_insert( iv_package ).

    lv_formname = ms_item-obj_name.

    TRY.
        lo_sf->enqueue( suppress_corr_check = space
                        master_language     = mv_language
                        mode                = 'INSERT'
                        formname            = lv_formname ).

        lo_sf->xml_upload( EXPORTING dom      = io_xml->get_raw( )->get_root_element( )
                                     formname = lv_formname
                                     language = mv_language
                           CHANGING  sform    = lo_res ).

        lo_res->store( im_formname = lo_res->header-formname
                       im_language = mv_language
                       im_active   = abap_true ).

        lo_sf->dequeue( lv_formname ).

      CATCH cx_ssf_fb INTO lx_error.
        lv_text = lx_error->get_text( ).
        zcx_abapgit_exception=>raise( |{ ms_item-obj_type } { ms_item-obj_name }: { lv_text } | ).
    ENDTRY.

  ENDMETHOD.

  METHOD zif_abapgit_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE zcl_abapgit_comparison_null.
  ENDMETHOD.

  METHOD zif_abapgit_object~is_locked.

    rv_is_locked = exists_a_lock_entry_for( iv_lock_object = 'E_SMFORM'
                                            iv_argument    = |{ ms_item-obj_name }| ).

  ENDMETHOD.

ENDCLASS.

fix jump to text module

SSFO: fix jump to text module

After this commit is applied jump to smartforms
text modules works as expected.


*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_SERVICES_GIT
*&---------------------------------------------------------------------*

CLASS lcl_services_git DEFINITION FINAL.
  PUBLIC SECTION.

    TYPES: BEGIN OF ty_commit_fields,
             repo_key        TYPE lcl_persistence_repo=>ty_repo-key,
             committer_name  TYPE string,
             committer_email TYPE string,
             author_name     TYPE string,
             author_email    TYPE string,
             comment         TYPE string,
             body            TYPE string,
           END OF ty_commit_fields.

    CLASS-METHODS pull
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS reset
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS create_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS switch_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS delete_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS commit
      IMPORTING io_repo   TYPE REF TO lcl_repo_online
                is_commit TYPE ty_commit_fields
                io_stage  TYPE REF TO lcl_stage
      RAISING   lcx_exception lcx_cancel.

ENDCLASS. " lcl_services_git

CLASS lcl_services_git IMPLEMENTATION.

  METHOD reset.

    DATA: lo_repo                   TYPE REF TO lcl_repo_online,
          lv_answer                 TYPE c LENGTH 1,
          lt_unnecessary_local_objs TYPE lif_defs=>ty_tadir_tt.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    IF lo_repo->is_write_protected( ) = abap_true.
      lcx_exception=>raise( 'Cannot reset. Local code is write-protected by repo config' ).
    ENDIF.

    lv_answer = lcl_popups=>popup_to_confirm(
      titlebar              = 'Warning'
      text_question         = 'Reset local objects?'
      text_button_1         = 'Ok'
      icon_button_1         = 'ICON_OKAY'
      text_button_2         = 'Cancel'
      icon_button_2         = 'ICON_CANCEL'
      default_button        = '2'
      display_cancel_button = abap_false ).                 "#EC NOTEXT

    IF lv_answer = '2'.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    lt_unnecessary_local_objs = lo_repo->get_unnecessary_local_objs( ).

    IF lines( lt_unnecessary_local_objs ) > 0.

      lv_answer = lcl_popups=>popup_to_confirm(
        titlebar              = 'Warning'
        text_question         = |Delete ({ lines( lt_unnecessary_local_objs ) }) unnecessary local objects?|
        text_button_1         = 'Yes'
        icon_button_1         = 'ICON_OKAY'
        text_button_2         = 'No'
        icon_button_2         = 'ICON_CANCEL'
        default_button        = '2'
        display_cancel_button = abap_false ).               "#EC NOTEXT

      IF lv_answer = '1'.
        lo_repo->delete_unnecessary_local_objs( ).
      ENDIF.

    ENDIF.

    lo_repo->deserialize( ).

  ENDMETHOD.

  METHOD create_branch.

    DATA: lv_name   TYPE string,
          lv_cancel TYPE abap_bool,
          lo_repo   TYPE REF TO lcl_repo_online.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    lcl_popups=>create_branch_popup(
      IMPORTING
        ev_name   = lv_name
        ev_cancel = lv_cancel ).
    IF lv_cancel = abap_true.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    ASSERT lv_name CP 'refs/heads/+*'.

    lcl_git_porcelain=>create_branch(
      io_repo = lo_repo
      iv_name = lv_name
      iv_from = lo_repo->get_sha1_local( ) ).

    " automatically switch to new branch
    lo_repo->set_branch_name( lv_name ).

    MESSAGE 'Switched to new branch' TYPE 'S' ##NO_TEXT.

  ENDMETHOD.

  METHOD pull.

    DATA: lo_repo TYPE REF TO lcl_repo_online.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    IF lo_repo->is_write_protected( ) = abap_true.
      lcx_exception=>raise( 'Cannot pull. Local code is write-protected by repo config' ).
    ENDIF.

    lo_repo->refresh( ).
    lo_repo->deserialize( ).

    COMMIT WORK.

  ENDMETHOD.                    "pull

  METHOD switch_branch.

    DATA: lo_repo   TYPE REF TO lcl_repo_online,
          ls_branch TYPE lcl_git_branch_list=>ty_git_branch.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    ls_branch = lcl_popups=>branch_list_popup(
      iv_url             = lo_repo->get_url( )
      iv_default_branch  = lo_repo->get_branch_name( )
      iv_show_new_option = abap_true ).
    IF ls_branch IS INITIAL.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    IF ls_branch-name = lcl_popups=>c_new_branch_label.
      create_branch( iv_key ).
      RETURN.
    ENDIF.

    lo_repo->set_branch_name( ls_branch-name ).

    COMMIT WORK.

    lo_repo->deserialize( ).

  ENDMETHOD.  "switch_branch

  METHOD delete_branch.

    DATA: lo_repo   TYPE REF TO lcl_repo_online,
          ls_branch TYPE lcl_git_branch_list=>ty_git_branch.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    ls_branch = lcl_popups=>branch_list_popup( lo_repo->get_url( ) ).
    IF ls_branch IS INITIAL.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    IF ls_branch-name = 'HEAD'.
      lcx_exception=>raise( 'Cannot delete HEAD' ).
    ELSEIF ls_branch-name = lo_repo->get_branch_name( ).
      lcx_exception=>raise( 'Switch branch before deleting current' ).
    ENDIF.

    lcl_git_porcelain=>delete_branch(
      io_repo   = lo_repo
      is_branch = ls_branch ).

    MESSAGE 'Branch deleted' TYPE 'S'.

  ENDMETHOD.  "delete_branch

  METHOD commit.

    DATA: ls_comment TYPE lif_defs=>ty_comment,
          lo_user    TYPE REF TO lcl_persistence_user.

    lo_user = lcl_app=>user( ).
    lo_user->set_repo_git_user_name( iv_url      = io_repo->get_url( )
                                     iv_username = is_commit-committer_name ).
    lo_user->set_repo_git_user_email( iv_url     = io_repo->get_url( )
                                      iv_email   = is_commit-committer_email ).

    IF is_commit-committer_name IS INITIAL.
      lcx_exception=>raise( 'Commit: Committer name empty' ).
    ELSEIF is_commit-committer_email IS INITIAL.
      lcx_exception=>raise( 'Commit: Committer email empty' ).
    ELSEIF is_commit-author_email IS NOT INITIAL AND is_commit-author_name IS INITIAL.
      lcx_exception=>raise( 'Commit: Author email empty' ). " Opposite should be OK ?
    ELSEIF is_commit-comment IS INITIAL.
      lcx_exception=>raise( 'Commit: empty comment' ).
    ENDIF.

    ls_comment-committer-name  = is_commit-committer_name.
    ls_comment-committer-email = is_commit-committer_email.
    ls_comment-author-name     = is_commit-author_name.
    ls_comment-author-email    = is_commit-author_email.
    ls_comment-comment         = is_commit-comment.

    IF NOT is_commit-body IS INITIAL.
      CONCATENATE ls_comment-comment '' is_commit-body
        INTO ls_comment-comment SEPARATED BY lif_defs=>gc_newline.
    ENDIF.

    io_repo->push( is_comment = ls_comment
                   io_stage   = io_stage ).

    COMMIT WORK.

  ENDMETHOD.  "commit

ENDCLASS. " lcl_services_git

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_SERVICES_GIT
*&---------------------------------------------------------------------*

CLASS lcl_services_git DEFINITION FINAL.
  PUBLIC SECTION.

    TYPES: BEGIN OF ty_commit_fields,
             repo_key        TYPE lcl_persistence_repo=>ty_repo-key,
             committer_name  TYPE string,
             committer_email TYPE string,
             author_name     TYPE string,
             author_email    TYPE string,
             comment         TYPE string,
             body            TYPE string,
           END OF ty_commit_fields.

    CLASS-METHODS pull
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS reset
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS create_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS switch_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS delete_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS commit
      IMPORTING io_repo   TYPE REF TO lcl_repo_online
                is_commit TYPE ty_commit_fields
                io_stage  TYPE REF TO lcl_stage
      RAISING   lcx_exception lcx_cancel.

ENDCLASS. " lcl_services_git

CLASS lcl_services_git IMPLEMENTATION.

  METHOD reset.

    DATA: lo_repo                   TYPE REF TO lcl_repo_online,
          lv_answer                 TYPE c LENGTH 1,
          lt_unnecessary_local_objs TYPE lif_defs=>ty_tadir_tt.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    IF lo_repo->is_write_protected( ) = abap_true.
      lcx_exception=>raise( 'Cannot reset. Local code is write-protected by repo config' ).
    ENDIF.

    lv_answer = lcl_popups=>popup_to_confirm(
      titlebar              = 'Warning'
      text_question         = 'Reset local objects?'
      text_button_1         = 'Ok'
      icon_button_1         = 'ICON_OKAY'
      text_button_2         = 'Cancel'
      icon_button_2         = 'ICON_CANCEL'
      default_button        = '2'
      display_cancel_button = abap_false ).                 "#EC NOTEXT

    IF lv_answer = '2'.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    lt_unnecessary_local_objs = lo_repo->get_unnecessary_local_objs( ).

    IF lines( lt_unnecessary_local_objs ) > 0.

      lv_answer = lcl_popups=>popup_to_confirm(
        titlebar              = 'Warning'
        text_question         = |Delete { lines( lt_unnecessary_local_objs ) } unnecessary local objects?|
        text_button_1         = 'Yes'
        icon_button_1         = 'ICON_OKAY'
        text_button_2         = 'No'
        icon_button_2         = 'ICON_CANCEL'
        default_button        = '2'
        display_cancel_button = abap_false ).               "#EC NOTEXT

      IF lv_answer = '1'.
        lo_repo->delete_unnecessary_local_objs( ).
      ENDIF.

    ENDIF.

    lo_repo->deserialize( ).

  ENDMETHOD.

  METHOD create_branch.

    DATA: lv_name   TYPE string,
          lv_cancel TYPE abap_bool,
          lo_repo   TYPE REF TO lcl_repo_online.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    lcl_popups=>create_branch_popup(
      IMPORTING
        ev_name   = lv_name
        ev_cancel = lv_cancel ).
    IF lv_cancel = abap_true.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    ASSERT lv_name CP 'refs/heads/+*'.

    lcl_git_porcelain=>create_branch(
      io_repo = lo_repo
      iv_name = lv_name
      iv_from = lo_repo->get_sha1_local( ) ).

    " automatically switch to new branch
    lo_repo->set_branch_name( lv_name ).

    MESSAGE 'Switched to new branch' TYPE 'S' ##NO_TEXT.

  ENDMETHOD.

  METHOD pull.

    DATA: lo_repo TYPE REF TO lcl_repo_online.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    IF lo_repo->is_write_protected( ) = abap_true.
      lcx_exception=>raise( 'Cannot pull. Local code is write-protected by repo config' ).
    ENDIF.

    lo_repo->refresh( ).
    lo_repo->deserialize( ).

    COMMIT WORK.

  ENDMETHOD.                    "pull

  METHOD switch_branch.

    DATA: lo_repo   TYPE REF TO lcl_repo_online,
          ls_branch TYPE lcl_git_branch_list=>ty_git_branch.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    ls_branch = lcl_popups=>branch_list_popup(
      iv_url             = lo_repo->get_url( )
      iv_default_branch  = lo_repo->get_branch_name( )
      iv_show_new_option = abap_true ).
    IF ls_branch IS INITIAL.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    IF ls_branch-name = lcl_popups=>c_new_branch_label.
      create_branch( iv_key ).
      RETURN.
    ENDIF.

    lo_repo->set_branch_name( ls_branch-name ).

    COMMIT WORK.

    lo_repo->deserialize( ).

  ENDMETHOD.  "switch_branch

  METHOD delete_branch.

    DATA: lo_repo   TYPE REF TO lcl_repo_online,
          ls_branch TYPE lcl_git_branch_list=>ty_git_branch.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    ls_branch = lcl_popups=>branch_list_popup( lo_repo->get_url( ) ).
    IF ls_branch IS INITIAL.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    IF ls_branch-name = 'HEAD'.
      lcx_exception=>raise( 'Cannot delete HEAD' ).
    ELSEIF ls_branch-name = lo_repo->get_branch_name( ).
      lcx_exception=>raise( 'Switch branch before deleting current' ).
    ENDIF.

    lcl_git_porcelain=>delete_branch(
      io_repo   = lo_repo
      is_branch = ls_branch ).

    MESSAGE 'Branch deleted' TYPE 'S'.

  ENDMETHOD.  "delete_branch

  METHOD commit.

    DATA: ls_comment TYPE lif_defs=>ty_comment,
          lo_user    TYPE REF TO lcl_persistence_user.

    lo_user = lcl_app=>user( ).
    lo_user->set_repo_git_user_name( iv_url      = io_repo->get_url( )
                                     iv_username = is_commit-committer_name ).
    lo_user->set_repo_git_user_email( iv_url     = io_repo->get_url( )
                                      iv_email   = is_commit-committer_email ).

    IF is_commit-committer_name IS INITIAL.
      lcx_exception=>raise( 'Commit: Committer name empty' ).
    ELSEIF is_commit-committer_email IS INITIAL.
      lcx_exception=>raise( 'Commit: Committer email empty' ).
    ELSEIF is_commit-author_email IS NOT INITIAL AND is_commit-author_name IS INITIAL.
      lcx_exception=>raise( 'Commit: Author email empty' ). " Opposite should be OK ?
    ELSEIF is_commit-comment IS INITIAL.
      lcx_exception=>raise( 'Commit: empty comment' ).
    ENDIF.

    ls_comment-committer-name  = is_commit-committer_name.
    ls_comment-committer-email = is_commit-committer_email.
    ls_comment-author-name     = is_commit-author_name.
    ls_comment-author-email    = is_commit-author_email.
    ls_comment-comment         = is_commit-comment.

    IF NOT is_commit-body IS INITIAL.
      CONCATENATE ls_comment-comment '' is_commit-body
        INTO ls_comment-comment SEPARATED BY lif_defs=>gc_newline.
    ENDIF.

    io_repo->push( is_comment = ls_comment
                   io_stage   = io_stage ).

    COMMIT WORK.

  ENDMETHOD.  "commit

ENDCLASS. " lcl_services_git

change popup text

change popup text


CLASS zcl_abapgit_gui_page_code_insp DEFINITION PUBLIC FINAL CREATE PUBLIC
    INHERITING FROM zcl_abapgit_gui_page.

  PUBLIC SECTION.
    INTERFACES: zif_abapgit_gui_page_hotkey.

    METHODS:
      constructor
        IMPORTING
          io_repo  TYPE REF TO zcl_abapgit_repo
          io_stage TYPE REF TO zcl_abapgit_stage OPTIONAL
        RAISING
          zcx_abapgit_exception,

      zif_abapgit_gui_page~on_event
        REDEFINITION,

      zif_abapgit_gui_page~render
        REDEFINITION.

  PROTECTED SECTION.
    DATA: mo_repo TYPE REF TO zcl_abapgit_repo.

    METHODS:
      render_content REDEFINITION.

  PRIVATE SECTION.
    CONSTANTS:
      BEGIN OF c_actions,
        stage  TYPE string VALUE 'stage' ##NO_TEXT,
        commit TYPE string VALUE 'commit' ##NO_TEXT,
        rerun  TYPE string VALUE 'rerun' ##NO_TEXT,
      END OF c_actions.

    DATA:
      mt_result TYPE scit_alvlist,
      mo_stage  TYPE REF TO zcl_abapgit_stage.

    METHODS:
      build_menu
        RETURNING
          VALUE(ro_menu) TYPE REF TO zcl_abapgit_html_toolbar
        RAISING
          zcx_abapgit_exception,

      run_code_inspector
        RAISING
          zcx_abapgit_exception,

      has_inspection_errors
        RETURNING
          VALUE(rv_has_inspection_errors) TYPE abap_bool,

      is_stage_allowed
        RETURNING
          VALUE(rv_is_stage_allowed) TYPE abap_bool,
      jump
        IMPORTING
          is_item TYPE zif_abapgit_definitions=>ty_item
        RAISING
          zcx_abapgit_exception.

ENDCLASS.

CLASS zcl_abapgit_gui_page_code_insp IMPLEMENTATION.

  METHOD build_menu.

    DATA: lv_opt TYPE c LENGTH 1.

    CREATE OBJECT ro_menu.

    ro_menu->add( iv_txt = 'Re-Run'
                  iv_act = c_actions-rerun
                  iv_cur = abap_false ) ##NO_TEXT.

    IF is_stage_allowed( ) = abap_false.
      lv_opt = zif_abapgit_definitions=>c_html_opt-crossout.
    ENDIF.

    IF mo_repo->is_offline( ) = abap_true.
      RETURN.
    ENDIF.

    IF mo_stage IS BOUND.

      " Staging info already available, we can directly
      " offer to commit

      ro_menu->add( iv_txt = 'Commit'
                    iv_act = c_actions-commit
                    iv_cur = abap_false
                    iv_opt = lv_opt ) ##NO_TEXT.

    ELSE.

      ro_menu->add( iv_txt = 'Stage'
                    iv_act = c_actions-stage
                    iv_cur = abap_false
                    iv_opt = lv_opt ) ##NO_TEXT.

    ENDIF.

  ENDMETHOD.

  METHOD constructor.
    super->constructor( ).
    mo_repo ?= io_repo.
    mo_stage = io_stage.
    ms_control-page_title = 'Code Inspector'.
    run_code_inspector( ).
  ENDMETHOD.  " constructor.

  METHOD has_inspection_errors.

    READ TABLE mt_result TRANSPORTING NO FIELDS
                         WITH KEY kind = 'E'.
    rv_has_inspection_errors = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD is_stage_allowed.

    rv_is_stage_allowed =  boolc( NOT ( mo_repo->get_local_settings( )-block_commit = abap_true
                                           AND has_inspection_errors( ) = abap_true ) ).

  ENDMETHOD.

  METHOD jump.

    DATA: lo_test               TYPE REF TO cl_ci_test_root,
          li_code_inspector     TYPE REF TO zif_abapgit_code_inspector,
          ls_info               TYPE scir_rest,
          lo_result             TYPE REF TO cl_ci_result_root,
          lv_check_variant_name TYPE sci_chkv,
          lv_package            TYPE devclass.

    FIELD-SYMBOLS: <ls_result> TYPE scir_alvlist.

    READ TABLE mt_result WITH KEY objtype = is_item-obj_type
                                  objname = is_item-obj_name
                         ASSIGNING <ls_result>.
    ASSERT sy-subrc = 0.

    lv_package = mo_repo->get_package( ).
    lv_check_variant_name = mo_repo->get_local_settings( )-code_inspector_check_variant.

    li_code_inspector = zcl_abapgit_factory=>get_code_inspector(
        iv_package            = lv_package
        iv_check_variant_name = lv_check_variant_name ).

    " see SCI_LCL_DYNP_530 / HANDLE_DOUBLE_CLICK

    MOVE-CORRESPONDING <ls_result> TO ls_info.

    TRY.
        lo_test ?= cl_ci_tests=>get_test_ref( <ls_result>-test ).

      CATCH cx_root.
        zcx_abapgit_exception=>raise( |Jump to object not supported in your NW release|  ).
    ENDTRY.

    lo_result = lo_test->get_result_node( <ls_result>-kind ).

    lo_result->set_info( ls_info ).
    lo_result->if_ci_test~navigate( ).

  ENDMETHOD.

  METHOD render_content.

    DATA: lv_check_variant TYPE sci_chkv,
          lv_class         TYPE string,
          lv_line          TYPE string.
    FIELD-SYMBOLS: <ls_result> TYPE scir_alvlist.

    CREATE OBJECT ro_html.

    lv_check_variant = mo_repo->get_local_settings( )-code_inspector_check_variant.

    IF lv_check_variant IS INITIAL.
      ro_html->add( |No check variant maintained in repo settings.| ).
      RETURN.
    ENDIF.

    ro_html->add( '

' ).

    ro_html->add( |Code inspector check variant: {
                    mo_repo->get_local_settings( )-code_inspector_check_variant
                  }
| ).

    IF lines( mt_result ) = 0.
      ro_html->add( '

No code inspector findings
' ).
    ENDIF.

    ro_html->add( |
| ).

    LOOP AT mt_result ASSIGNING <ls_result>.

      ro_html->add( '
' ).
      ro_html->add_a( iv_txt = |{ <ls_result>-objtype } { <ls_result>-objname }|
                      iv_act = |{ <ls_result>-objtype }{ <ls_result>-objname }|
                      iv_typ = zif_abapgit_definitions=>c_action_type-sapevent ).
      ro_html->add( '
' ).

      CASE <ls_result>-kind.
        WHEN 'E'.
          lv_class = 'error'.
        WHEN 'W'.
          lv_class = 'warning'.
        WHEN OTHERS.
          lv_class = 'grey'.
      ENDCASE.

      CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'
        EXPORTING
          input  = <ls_result>-line
        IMPORTING
          output = lv_line.

      ro_html->add( |
Line { lv_line }: { <ls_result>-text }

| ).
    ENDLOOP.

    ro_html->add( '
' ).

  ENDMETHOD.  "render_content

  METHOD run_code_inspector.

    mt_result = mo_repo->run_code_inspector( ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_page~on_event.

    DATA: lo_repo_online TYPE REF TO zcl_abapgit_repo_online,
          ls_item        TYPE zif_abapgit_definitions=>ty_item.

    CASE iv_action.
      WHEN c_actions-stage.

        lo_repo_online ?= mo_repo.

        IF is_stage_allowed( ) = abap_true.
          " we need to refresh as the source might have changed
          lo_repo_online->refresh( ).

          CREATE OBJECT ei_page TYPE zcl_abapgit_gui_page_stage
            EXPORTING
              io_repo = lo_repo_online.
          ev_state = zif_abapgit_definitions=>c_event_state-new_page.

        ELSE.

          ei_page = me.
          ev_state = zif_abapgit_definitions=>c_event_state-no_more_act.

        ENDIF.

      WHEN c_actions-commit.

        lo_repo_online ?= mo_repo.

        IF is_stage_allowed( ) = abap_true.

          CREATE OBJECT ei_page TYPE zcl_abapgit_gui_page_commit
            EXPORTING
              io_repo  = lo_repo_online
              io_stage = mo_stage.
          ev_state = zif_abapgit_definitions=>c_event_state-new_page.

        ELSE.

          ei_page = me.
          ev_state = zif_abapgit_definitions=>c_event_state-no_more_act.

        ENDIF.

      WHEN c_actions-rerun.

        run_code_inspector( ).

        ei_page = me.
        ev_state = zif_abapgit_definitions=>c_event_state-re_render.

      WHEN OTHERS.

        ls_item-obj_type = iv_action(4).
        ls_item-obj_name = iv_action+4(*).

        jump( ls_item ).

*        zcl_abapgit_objects=>jump( ls_item ).

        ev_state = zif_abapgit_definitions=>c_event_state-no_more_act.

    ENDCASE.

  ENDMETHOD.

  METHOD zif_abapgit_gui_page~render.

    ms_control-page_menu = build_menu( ).
    ro_html = super->zif_abapgit_gui_page~render( ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_page_hotkey~get_hotkey_actions.

    DATA: ls_hotkey_action LIKE LINE OF rt_hotkey_actions.

    ls_hotkey_action-name           = |Code Inspector: Stage|.
    ls_hotkey_action-action         = c_actions-stage.
    ls_hotkey_action-default_hotkey = |s|.
    INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.

    ls_hotkey_action-name           = |Code Inspector: Re-Run|.
    ls_hotkey_action-action         = c_actions-rerun.
    ls_hotkey_action-default_hotkey = |r|.
    INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.

  ENDMETHOD.

ENDCLASS.

CLASS zcl_abapgit_gui_page_code_insp DEFINITION PUBLIC FINAL CREATE PUBLIC
    INHERITING FROM zcl_abapgit_gui_page.

  PUBLIC SECTION.
    INTERFACES: zif_abapgit_gui_page_hotkey.

    METHODS:
      constructor
        IMPORTING
          io_repo  TYPE REF TO zcl_abapgit_repo
          io_stage TYPE REF TO zcl_abapgit_stage OPTIONAL
        RAISING
          zcx_abapgit_exception,

      zif_abapgit_gui_page~on_event
        REDEFINITION,

      zif_abapgit_gui_page~render
        REDEFINITION.

  PROTECTED SECTION.
    DATA: mo_repo TYPE REF TO zcl_abapgit_repo.

    METHODS:
      render_content REDEFINITION.

  PRIVATE SECTION.
    CONSTANTS:
      BEGIN OF c_actions,
        stage  TYPE string VALUE 'stage' ##NO_TEXT,
        commit TYPE string VALUE 'commit' ##NO_TEXT,
        rerun  TYPE string VALUE 'rerun' ##NO_TEXT,
      END OF c_actions.

    DATA:
      mt_result TYPE scit_alvlist,
      mo_stage  TYPE REF TO zcl_abapgit_stage.

    METHODS:
      build_menu
        RETURNING
          VALUE(ro_menu) TYPE REF TO zcl_abapgit_html_toolbar
        RAISING
          zcx_abapgit_exception,

      run_code_inspector
        RAISING
          zcx_abapgit_exception,

      has_inspection_errors
        RETURNING
          VALUE(rv_has_inspection_errors) TYPE abap_bool,

      is_stage_allowed
        RETURNING
          VALUE(rv_is_stage_allowed) TYPE abap_bool,
      jump
        IMPORTING
          is_item TYPE zif_abapgit_definitions=>ty_item
        RAISING
          zcx_abapgit_exception.

ENDCLASS.

CLASS zcl_abapgit_gui_page_code_insp IMPLEMENTATION.

  METHOD build_menu.

    DATA: lv_opt TYPE c LENGTH 1.

    CREATE OBJECT ro_menu.

    ro_menu->add( iv_txt = 'Re-Run'
                  iv_act = c_actions-rerun
                  iv_cur = abap_false ) ##NO_TEXT.

    IF is_stage_allowed( ) = abap_false.
      lv_opt = zif_abapgit_definitions=>c_html_opt-crossout.
    ENDIF.

    IF mo_repo->is_offline( ) = abap_true.
      RETURN.
    ENDIF.

    IF mo_stage IS BOUND.

      " Staging info already available, we can directly
      " offer to commit

      ro_menu->add( iv_txt = 'Commit'
                    iv_act = c_actions-commit
                    iv_cur = abap_false
                    iv_opt = lv_opt ) ##NO_TEXT.

    ELSE.

      ro_menu->add( iv_txt = 'Stage'
                    iv_act = c_actions-stage
                    iv_cur = abap_false
                    iv_opt = lv_opt ) ##NO_TEXT.

    ENDIF.

  ENDMETHOD.

  METHOD constructor.
    super->constructor( ).
    mo_repo ?= io_repo.
    mo_stage = io_stage.
    ms_control-page_title = 'Code Inspector'.
    run_code_inspector( ).
  ENDMETHOD.  " constructor.

  METHOD has_inspection_errors.

    READ TABLE mt_result TRANSPORTING NO FIELDS
                         WITH KEY kind = 'E'.
    rv_has_inspection_errors = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD is_stage_allowed.

    rv_is_stage_allowed =  boolc( NOT ( mo_repo->get_local_settings( )-block_commit = abap_true
                                           AND has_inspection_errors( ) = abap_true ) ).

  ENDMETHOD.

  METHOD jump.

    DATA: lo_test               TYPE REF TO cl_ci_test_root,
          li_code_inspector     TYPE REF TO zif_abapgit_code_inspector,
          ls_info               TYPE scir_rest,
          lo_result             TYPE REF TO cl_ci_result_root,
          lv_check_variant_name TYPE sci_chkv,
          lv_package            TYPE devclass.

    FIELD-SYMBOLS: <ls_result> TYPE scir_alvlist.

    READ TABLE mt_result WITH KEY objtype = is_item-obj_type
                                  objname = is_item-obj_name
                         ASSIGNING <ls_result>.
    ASSERT sy-subrc = 0.

    lv_package = mo_repo->get_package( ).
    lv_check_variant_name = mo_repo->get_local_settings( )-code_inspector_check_variant.

    li_code_inspector = zcl_abapgit_factory=>get_code_inspector(
        iv_package            = lv_package
        iv_check_variant_name = lv_check_variant_name ).

    " see SCI_LCL_DYNP_530 / HANDLE_DOUBLE_CLICK

    MOVE-CORRESPONDING <ls_result> TO ls_info.

    TRY.
        lo_test ?= cl_ci_tests=>get_test_ref( <ls_result>-test ).

      CATCH cx_root.
        zcx_abapgit_exception=>raise( |Jump to object not supported in your NW release|  ).
    ENDTRY.

    lo_result = lo_test->get_result_node( <ls_result>-kind ).

    lo_result->set_info( ls_info ).
    lo_result->if_ci_test~navigate( ).

  ENDMETHOD.

  METHOD render_content.

    DATA: lv_check_variant TYPE sci_chkv,
          lv_class         TYPE string,
          lv_line          TYPE string.
    FIELD-SYMBOLS: <ls_result> TYPE scir_alvlist.

    CREATE OBJECT ro_html.

    lv_check_variant = mo_repo->get_local_settings( )-code_inspector_check_variant.

    IF lv_check_variant IS INITIAL.
      ro_html->add( |No check variant maintained in repo settings.| ).
      RETURN.
    ENDIF.

    ro_html->add( '

' ).

    ro_html->add( |Code inspector check variant: {
                    mo_repo->get_local_settings( )-code_inspector_check_variant
                  }
| ).

    IF lines( mt_result ) = 0.
      ro_html->add( '

No code inspector findings
' ).
    ENDIF.

    ro_html->add( |
| ).

    LOOP AT mt_result ASSIGNING <ls_result>.

      ro_html->add( '
' ).
      ro_html->add_a( iv_txt = |{ <ls_result>-objtype } { <ls_result>-objname }|
                      iv_act = |{ <ls_result>-objtype }{ <ls_result>-objname }|
                      iv_typ = zif_abapgit_definitions=>c_action_type-sapevent ).
      ro_html->add( '
' ).

      CASE <ls_result>-kind.
        WHEN 'E'.
          lv_class = 'error'.
        WHEN 'W'.
          lv_class = 'warning'.
        WHEN OTHERS.
          lv_class = 'grey'.
      ENDCASE.

      CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'
        EXPORTING
          input  = <ls_result>-line
        IMPORTING
          output = lv_line.

      ro_html->add( |
Line { lv_line }: { <ls_result>-text }

| ).
    ENDLOOP.

    ro_html->add( '
' ).

  ENDMETHOD.  "render_content

  METHOD run_code_inspector.

    mt_result = mo_repo->run_code_inspector( ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_page~on_event.

    DATA: lo_repo_online TYPE REF TO zcl_abapgit_repo_online,
          ls_item        TYPE zif_abapgit_definitions=>ty_item.

    CASE iv_action.
      WHEN c_actions-stage.

        lo_repo_online ?= mo_repo.

        IF is_stage_allowed( ) = abap_true.
          " we need to refresh as the source might have changed
          lo_repo_online->refresh( ).

          CREATE OBJECT ei_page TYPE zcl_abapgit_gui_page_stage
            EXPORTING
              io_repo = lo_repo_online.
          ev_state = zif_abapgit_definitions=>c_event_state-new_page.

        ELSE.

          ei_page = me.
          ev_state = zif_abapgit_definitions=>c_event_state-no_more_act.

        ENDIF.

      WHEN c_actions-commit.

        lo_repo_online ?= mo_repo.

        IF is_stage_allowed( ) = abap_true.

          CREATE OBJECT ei_page TYPE zcl_abapgit_gui_page_commit
            EXPORTING
              io_repo  = lo_repo_online
              io_stage = mo_stage.
          ev_state = zif_abapgit_definitions=>c_event_state-new_page.

        ELSE.

          ei_page = me.
          ev_state = zif_abapgit_definitions=>c_event_state-no_more_act.

        ENDIF.

      WHEN c_actions-rerun.

        run_code_inspector( ).

        ei_page = me.
        ev_state = zif_abapgit_definitions=>c_event_state-re_render.

      WHEN zif_abapgit_definitions=>c_action-abapgit_home.
        RETURN.

      WHEN OTHERS.

        ls_item-obj_type = iv_action(4).
        ls_item-obj_name = iv_action+4(*).

        jump( ls_item ).

*        zcl_abapgit_objects=>jump( ls_item ).

        ev_state = zif_abapgit_definitions=>c_event_state-no_more_act.

    ENDCASE.

  ENDMETHOD.

  METHOD zif_abapgit_gui_page~render.

    ms_control-page_menu = build_menu( ).
    ro_html = super->zif_abapgit_gui_page~render( ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_page_hotkey~get_hotkey_actions.

    DATA: ls_hotkey_action LIKE LINE OF rt_hotkey_actions.

    ls_hotkey_action-name           = |Code Inspector: Stage|.
    ls_hotkey_action-action         = c_actions-stage.
    ls_hotkey_action-default_hotkey = |s|.
    INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.

    ls_hotkey_action-name           = |Code Inspector: Re-Run|.
    ls_hotkey_action-action         = c_actions-rerun.
    ls_hotkey_action-default_hotkey = |r|.
    INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.

  ENDMETHOD.

ENDCLASS.

handle abapgit_home in CI page

handle abapgit_home in CI page