Экраны, окна и диалоги как объекты ABAP в SAP R/3

При разработке приложений для SAP R3  пришлось столкнуться с таким фактом, что абсолютное большинство программистов на языке ABAP пишут в процедурном стиле и ООП используют только для привязки событий ALV компонентов, каждый раз заново изобретая велосипед, из-за чего подход к построению интерфейсов в разных транзакциях зависит целиком от вменяемости конкретного разработчика и для доработки программы в каждом конкретном случае приходится тратить много времени и сил просто для разбора исходных текстов. С целью унификации подхода к разработке интерфейса после прочтения книги Igor Barbaric "Design Patterns in Object-Oriented ABAP" была предпринята попытка создание ООП-каркаса для построения GUI на языке ABAP. Каркас включает в себя классы-обвязки для работы с Enjoy-controls: ALV-Grid, ALV-Tree и т.д.


Соглашения для написания классов
  1. методы, которые не могут быть абстрактными начинаются с do_XXX, и если возможна реализация в потомке, то в предке создается заглушка
  2. методы, котрые могут быть абстрактными и перекрытыми в потомках  начинаются с get_XXX и set_XXX

Соглашения для использования логики экранов
  1. Все объекты экранов помещаются в стек и управляются с помощью единичного объекта lcl_gui_application
  2. Для обработки используются модули:
    1. status_window (PBO)
    2. user_command_window (PAI)
    3. user_command_exit (USER-EXIT)

TYPE-POOLS: slis.

*----------------------------------------------------------------------*
*       INTERFACE lif_gui_screen
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
INTERFACE lif_gui_screen.

  " Вызвать экран
  METHODS: call_screen.

ENDINTERFACE.                    "lif_gui_screen

*----------------------------------------------------------------------*
*       INTERFACE lif_gui_dialog
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
INTERFACE lif_gui_dialog.

  " Показать диалог
  METHODS: call_dialog IMPORTING i_action TYPE i OPTIONAL
                                      i_x TYPE i OPTIONAL
                                      i_y TYPE i OPTIONAL
                                      i_m TYPE i OPTIONAL
                                      i_n TYPE i OPTIONAL.

ENDINTERFACE.                    "lif_gui_dialog

*----------------------------------------------------------------------*
*       INTERFACE lif_gui_view_screen
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
INTERFACE lif_gui_view_screen.

  " Сохранить изменения в записи
  METHODS: save_record.
  " Перейти на следующую запись
  METHODS: next_record.
  " Перейти на предидущую запись
  METHODS: prev_record.

ENDINTERFACE.                    "lif_gui_view_screen

*----------------------------------------------------------------------*
*       INTERFACE lif_gui_view_dialog
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
INTERFACE lif_gui_view_dialog.

  " Получить данные
  METHODS: read_record CHANGING i_record TYPE REF TO data.
  " Установить данные
  METHODS: init_record IMPORTING i_record TYPE REF TO data.
  " Получить режим
  METHODS: read_action RETURNING value(r_result) TYPE i.
  " Установить режим
  METHODS: init_action IMPORTING value(i_action) TYPE i.

ENDINTERFACE.                    "lif_gui_view_dialog

*----------------------------------------------------------------------*
*       INTERFACE lif_gui_process_screen
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
INTERFACE lif_gui_progress_indicator.

  METHODS:
    progress_indicator
      IMPORTING
        i_perc TYPE i
        i_text TYPE syucomm.

ENDINTERFACE.                    "lif_gui_process_screen


CLASS lcl_gui_window DEFINITION DEFERRED.

*----------------------------------------------------------------------*
*       CLASS lcl_gui_utils  DEFINITIO
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_utils DEFINITION
  ABSTRACT.

  PUBLIC SECTION.

    CLASS-METHODS:
      " Создание списка полей для ALV-Grid
      build_dd_fieldcatalog
        IMPORTING
          value(i_program_name) TYPE  sy-repid OPTIONAL
          value(i_internal_tabname) TYPE slis_tabname OPTIONAL
          value(i_structure_name) TYPE dd02l-tabname OPTIONAL
          value(i_client_never_display) TYPE  slis_char_1 DEFAULT 'X'
          value(i_inclname) TYPE  trdir-name OPTIONAL
          value(i_bypassing_buffer) TYPE  char01 OPTIONAL
          value(i_buffer_active) TYPE  char01 OPTIONAL
        EXPORTING
          et_fldcat_lvc TYPE  lvc_t_fcat
        CHANGING
          itab TYPE STANDARD TABLE
        EXCEPTIONS
            inconsistent_interface
            program_error
            no_fields
            it_data_missing,
      " Очистка объекта
      free_and_initial
        CHANGING
          ch_window TYPE REF TO lcl_gui_window.

ENDCLASS.                    "lcl_gui_utils  DEFINITIO


*----------------------------------------------------------------------*
*       CLASS lcl_gui_application  DEFINITIO
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_application DEFINITION
  ABSTRACT.

  PUBLIC SECTION.

    METHODS:
      " Конструктор
      constructor,
      " Стартовый метод для транзакций
      start ABSTRACT.

    " PBO
    CLASS-METHODS: pbo IMPORTING i_ucomm TYPE syucomm.
    " PAI
    CLASS-METHODS: pai IMPORTING i_ucomm TYPE syucomm.
    " User-exit
    CLASS-METHODS: user_exit IMPORTING i_ucomm TYPE syucomm.

    " Зарегистрировать окно
    CLASS-METHODS: register IMPORTING i_window TYPE REF TO lcl_gui_window.
    " Вернуться
    CLASS-METHODS: back.
    " Выход
    CLASS-METHODS: exit.

  PROTECTED SECTION.

    " Очистить стек
    CLASS-METHODS: clear.
    " Добавить экран в стек
    CLASS-METHODS: push IMPORTING i_window TYPE REF TO lcl_gui_window.
    " Получить экран из стека
    CLASS-METHODS: pick RETURNING value(r_result) TYPE REF TO lcl_gui_window
                        EXCEPTIONS ex_empty no_result.
    " Извлечь экран из стека
    CLASS-METHODS: pop RETURNING value(r_result) TYPE REF TO lcl_gui_window
                       EXCEPTIONS ex_empty no_result.

    " Экемпляр
    CLASS-DATA: o_this TYPE REF TO lcl_gui_application.

  PRIVATE SECTION.

    " Окна
    CLASS-DATA: o_stack TYPE osreftab.
    " Номер экрана выбора
    CLASS-DATA: m_dynnr TYPE sydynnr VALUE IS INITIAL.

ENDCLASS.                    "lcl_gui_application  DEFINITIO

*----------------------------------------------------------------------*
*  DATA ok_code TYPE syucomm
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
DATA ok_code TYPE syucomm.

*----------------------------------------------------------------------*
*  MODULE status_window OUTPUT
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
MODULE status_window OUTPUT.

  ok_code = sy-ucomm.

  CALL METHOD lcl_gui_application=>pbo( ok_code ).

ENDMODULE.                    "status_window OUTPUT

*----------------------------------------------------------------------*
*  MODULE user_command_window INPUT
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
MODULE user_command_window INPUT.

  ok_code = sy-ucomm.

  CALL METHOD lcl_gui_application=>pai( ok_code ).

ENDMODULE.                    "user_command_window INPUT

*----------------------------------------------------------------------*
*  MODULE user_command_exit INPUT
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
MODULE user_command_exit INPUT.

  ok_code = sy-ucomm.

  CALL METHOD lcl_gui_application=>user_exit( ok_code ).

ENDMODULE.                    "user_command_exit INPUT


*----------------------------------------------------------------------*
*       CLASS lcl_gui_window  DEFINITIO
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_window DEFINITION
  ABSTRACT.

  PUBLIC SECTION.

    CONSTANTS: c_cancel TYPE i VALUE 0,
               c_browse TYPE i VALUE 1,
               c_create TYPE i VALUE 2,
               c_update TYPE i VALUE 3,
               c_delete TYPE i VALUE 4.

    " Получить экземпляр
    CLASS-METHODS: get_window IMPORTING value(i_class) TYPE string
                                        value(i_dynnr) TYPE sydynnr
                              RETURNING value(r_result) TYPE REF TO lcl_gui_window.

    METHODS: constructor IMPORTING i_dynnr TYPE sydynnr.
    METHODS: free.

    " Логика PBO
    METHODS: do_pbo IMPORTING i_ucomm TYPE syucomm.
    " Логика PBI
    METHODS: do_pai IMPORTING i_ucomm TYPE syucomm.
    " Логика PBI
    METHODS: do_exit CHANGING ch_ucomm TYPE syucomm.

    " Получить номер экрана
    METHODS: get_dynnr RETURNING value(r_result) TYPE sydynnr.

  PRIVATE SECTION.

    " Номер экрана
    DATA: m_dynnr TYPE sydynnr.

ENDCLASS.                    "lcl_gui_window  DEFINITIO


*----------------------------------------------------------------------*
*       CLASS lcl_gui_screen  DEFINITIO
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_screen DEFINITION
  ABSTRACT
  INHERITING FROM lcl_gui_window.

  PUBLIC SECTION.

    INTERFACES: lif_gui_screen.
    " Вызов экрана
    ALIASES: call_screen FOR lif_gui_screen~call_screen.

    " Получить экземпляр
    CLASS-METHODS: get_screen IMPORTING value(i_class) TYPE string
                                        value(i_dynnr) TYPE sydynnr
                              RETURNING value(r_result) TYPE REF TO lif_gui_screen.

    " Free
    METHODS: free REDEFINITION.
    " Логика PBO
    METHODS: do_pbo REDEFINITION.
    " Логика PBI
    METHODS: do_pai REDEFINITION.

  PROTECTED SECTION.

    " Вызвать экран
    METHODS: do_call_screen FINAL.
    " Инициализиировать экран
    METHODS: do_init_screen.

ENDCLASS.                    "lcl_gui_screen  DEFINITIO

*----------------------------------------------------------------------*
*       CLASS lcl_gui_dialog  DEFINITIO
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_dialog DEFINITION
  INHERITING FROM lcl_gui_window.

  PUBLIC SECTION.

    INTERFACES: lif_gui_dialog.

    CONSTANTS:
      c_applyfunc   TYPE syucomm VALUE 'APPLY',
      c_cancelfunc  TYPE syucomm VALUE 'CANCEL'.

    " Вызов
    ALIASES:
      call_dialog FOR lif_gui_dialog~call_dialog.

    " Получить экземпляр
    CLASS-METHODS: get_dialog IMPORTING value(i_class) TYPE string
                                        value(i_dynnr) TYPE sydynnr
                                              i_screen TYPE REF TO lcl_gui_screen
                                                   i_x TYPE i OPTIONAL
                                                   i_y TYPE i OPTIONAL
                                                   i_m TYPE i OPTIONAL
                                                   i_n TYPE i OPTIONAL
                              RETURNING value(r_result) TYPE REF TO lif_gui_dialog.

    METHODS: constructor IMPORTING i_dynnr  TYPE sydynnr
                                   i_screen TYPE REF TO lcl_gui_screen
                                                   OPTIONAL
                                        i_x TYPE i OPTIONAL
                                        i_y TYPE i OPTIONAL
                                        i_m TYPE i OPTIONAL
                                        i_n TYPE i OPTIONAL.
    " Логика PBO
    METHODS: do_pbo REDEFINITION.
    " Логика PBI
    METHODS: do_pai REDEFINITION.
    " Вызывающий экран
    METHODS: set_screen IMPORTING i_screen TYPE REF TO lcl_gui_screen.
    " Вызывающий экран
    METHODS: get_screen RETURNING value(r_result) TYPE REF TO lcl_gui_screen.
    " Местоположение
    METHODS: set_bounds IMPORTING i_x TYPE i
                                  i_y TYPE i
                                  i_m TYPE i OPTIONAL
                                  i_n TYPE i OPTIONAL.
    " Местоположение
    METHODS: get_bounds EXPORTING e_x TYPE i
                                  e_y TYPE i
                                  e_m TYPE i
                                  e_n TYPE i.

  PROTECTED SECTION.

    " Показать диалог
    METHODS:
      do_call_dialog FINAL
        IMPORTING
          i_action TYPE i OPTIONAL
               i_x TYPE i OPTIONAL
               i_y TYPE i OPTIONAL
               i_m TYPE i OPTIONAL
               i_n TYPE i OPTIONAL.

    " Получить режим
    METHODS: do_read_action RETURNING value(r_result) TYPE i.
    " Установить режим
    METHODS: do_init_action IMPORTING value(i_action) TYPE i.

    " Принять
    METHODS: do_apply_record.
    " Отмена
    METHODS: do_cancel_record.

    " Вызывающий экран
    DATA: m_screen TYPE REF TO lcl_gui_screen.
    " Режим действий
    DATA: m_action TYPE i.
    " Параметры
    DATA: m_x TYPE i,
          m_y TYPE i,
          m_m TYPE i,
          m_n TYPE i.

ENDCLASS.                    "lcl_gui_dialog  DEFINITIO

*----------------------------------------------------------------------*
*       CLASS lcl_gui_subscreen  DEFINITIO
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_subscreen DEFINITION
  ABSTRACT
  INHERITING FROM lcl_gui_window.

  PUBLIC SECTION.

    CLASS-METHODS:
      " PBO
      pbo
        IMPORTING
          i_ucomm TYPE syucomm,
      " PAI
      pai
        IMPORTING
          i_ucomm TYPE syucomm.

    METHODS:
      constructor
        IMPORTING
          i_dynnr TYPE sydynnr
          i_owner TYPE REF TO lcl_gui_window,

      " Логика PBO
      do_pbo REDEFINITION,
      " Логика PBI
      do_pai REDEFINITION.

  PROTECTED SECTION.

    METHODS:
      " Инициализация
      do_init_subscreen.

    CLASS-DATA:
      o_this TYPE REF TO lcl_gui_subscreen.

  PRIVATE SECTION.

    DATA:
       " Владелец
       m_owner TYPE REF TO lcl_gui_window.

ENDCLASS.                    "lcl_gui_subscreen  DEFINITIO

*----------------------------------------------------------------------*
*       CLASS lcl_gui_view_screen  DEFINITIO
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_view_screen DEFINITION
  ABSTRACT
  INHERITING FROM lcl_gui_screen.

  PUBLIC SECTION.

    INTERFACES: lif_gui_view_screen.

    " Сохранить изменения в записи
    ALIASES: save_record FOR lif_gui_view_screen~save_record.
    " Перейти на следующую запись
    ALIASES: next_record FOR lif_gui_view_screen~next_record.
    " Перейти на предидущую запись
    ALIASES: prev_record FOR lif_gui_view_screen~prev_record.


    " Логика PBO
    METHODS: do_pbo REDEFINITION.
    " Логика PBI
    METHODS: do_pai REDEFINITION.

  PROTECTED SECTION.

    " Инициировать диалог
    METHODS: do_active_dialog.
    " Просмотреть запись
    METHODS: do_browse_dialog.
    " Диалог для добавления
    METHODS: do_create_dialog.
    " Диалог для обновления
    METHODS: do_update_dialog.
    " Диалог для удаления
    METHODS: do_delete_dialog.

    " Сохранить активную запись
    METHODS: do_save_record.
    " Перейти на запись вверх
    METHODS: do_next_record RETURNING value(r_result) TYPE REF TO data.
    " Перейти на запись вниз
    METHODS: do_prev_record RETURNING value(r_result) TYPE REF TO data.

    " Получить активную запись
    METHODS: do_read_record RETURNING value(r_result) TYPE REF TO data.
    " Сохранить активную запись
    METHODS: do_init_record IMPORTING value(i_action) TYPE i
                                      value(i_record) TYPE REF TO data.

    " Проверить запись
    METHODS: do_check_record IMPORTING value(i_action) TYPE i
                                       value(i_record) TYPE REF TO data
                             RETURNING value(r_result) TYPE i.
    " Проверить роль
    METHODS: do_check_role IMPORTING value(i_action) TYPE i
                           RETURNING value(r_result) TYPE char1.

    " Создать запись
    METHODS: do_create_record IMPORTING value(i_record) TYPE REF TO data
                              EXCEPTIONS no_result.
    " Редактировать активную запись
    METHODS: do_update_record IMPORTING value(i_record) TYPE REF TO data
                              EXCEPTIONS no_result.
    " Удалить запись
    METHODS: do_delete_record IMPORTING value(i_record) TYPE REF TO data
                              EXCEPTIONS no_result.

    " CRUD - выбрать запись по ID
    METHODS: do_select_by_id IMPORTING i_record TYPE REF TO data
                             EXCEPTIONS no_result.
    " CRUD - создать запись по ID
    METHODS: do_create_by_id IMPORTING i_record TYPE REF TO data
                             EXCEPTIONS no_result.
    " CRUD - изменить запись по ID
    METHODS: do_update_by_id IMPORTING i_record TYPE REF TO data
                             EXCEPTIONS no_result.
    " CRUD - удалить запись по ID
    METHODS: do_delete_by_id IMPORTING i_record TYPE REF TO data
                             EXCEPTIONS no_result.

    " Получить имя структуры данных
    METHODS: get_structure_name ABSTRACT
                                RETURNING value(r_result) TYPE string.
    " Получить типизированную строку данных
    METHODS: get_structure_data ABSTRACT
                                RETURNING value(r_result) TYPE REF TO data.

    " Dialog
    DATA: m_dialog TYPE REF TO lif_gui_view_dialog.

ENDCLASS.                    "lcl_gui_view_screen  DEFINITIO

*----------------------------------------------------------------------*
*       CLASS lcl_gui_view_dialog  DEFINITIO
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_view_dialog DEFINITION
  ABSTRACT
  INHERITING FROM lcl_gui_dialog.

  PUBLIC SECTION.

    INTERFACES: lif_gui_view_dialog.

    " Получить данные
    ALIASES: read_record FOR lif_gui_view_dialog~read_record.
    " Установить данные
    ALIASES: init_record FOR lif_gui_view_dialog~init_record.
    " Получить режим
    ALIASES: read_action FOR lif_gui_view_dialog~read_action.
    " Установить режим
    ALIASES: init_action FOR lif_gui_view_dialog~init_action.


    " Логика PBO
    METHODS: do_pbo REDEFINITION.
    " Логика PBI
    METHODS: do_pai REDEFINITION.

  PROTECTED SECTION.

    " Принять
    METHODS: do_apply_record REDEFINITION.
    " Получить данные
    METHODS: do_read_record CHANGING i_record TYPE REF TO data.
    " Установить данные
    METHODS: do_init_record IMPORTING i_record TYPE REF TO data.
    " Сохранить текущую
    METHODS: do_save_record.
    " Перейти на запись вверх
    METHODS: do_next_record.
    " Перейти на запись вниз
    METHODS: do_prev_record.

ENDCLASS.                    "lcl_gui_view_dialog  DEFINITIO

*----------------------------------------------------------------------*
*       CLASS lcl_gui_view_subscreen  DEFINITIO
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_view_subscreen DEFINITION
  INHERITING FROM lcl_gui_subscreen
  ABSTRACT.

  PUBLIC SECTION.

    METHODS:
      " Проверить
      validate ABSTRACT
        EXCEPTIONS no_valid,
      " Получить данные
      get_data ABSTRACT
        CHANGING
          i_data TYPE REF TO data,
      " Установить данные
      set_data ABSTRACT
        IMPORTING
          i_data TYPE REF TO data,
      " Получить режим
      get_mode
        RETURNING value(result) TYPE i,
      " Установить режим
      set_mode
        IMPORTING value(i_mode) TYPE i.

  PRIVATE SECTION.

    DATA:
      " Режим
      m_mode TYPE i VALUE c_browse.

ENDCLASS.                    "lcl_gui_view_subscreen  DEFINITIO

*----------------------------------------------------------------------*
*       CLASS lcl_gui_grid_screen  DEFINITIO
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_grid_screen DEFINITION
  ABSTRACT
  INHERITING FROM lcl_gui_view_screen.

  PUBLIC SECTION.

    METHODS: free REDEFINITION.

  PROTECTED SECTION.

    " Инициализиировать экран
    METHODS: do_init_screen REDEFINITION.
    " Перейти на запись вверх
    METHODS: do_next_record REDEFINITION.
    " Перейти на запись вниз
    METHODS: do_prev_record REDEFINITION.

    " Получить активную запись
    METHODS: do_read_record REDEFINITION.
    " Сохранить активную запись
    METHODS: do_init_record REDEFINITION.

    " Вариант для ALVGRID
    METHODS: do_init_variant.
    " Layout ALVGRID
    METHODS: do_init_layout.
    " Поля ALVGRID
    METHODS: do_init_fields.
    " Специальные поля
    METHODS: do_init_groups.
    " Сортировка
    METHODS: do_init_sorted.
    " Получить данные
    METHODS: do_init_outtab.

    " Получить заголовок для ALVGrid
    METHODS: get_alvgrid_title ABSTRACT
                       RETURNING value(r_result) TYPE string.
    " Получить имя ALV контейнера
    METHODS: get_container_name ABSTRACT
                       RETURNING value(r_result) TYPE string.
    " Навигация
    METHODS: get_selected_rows EXCEPTIONS no_rows.
    METHODS: set_selected_rows EXCEPTIONS no_rows.
    " Установить обработчики для грида
    METHODS: set_alvgrid_handlers.
    " Устновить событие редактирования
    METHODS: set_alvgrid_edit_event.
    " Изменение выделеных строк
    METHODS: set_index_before_create.
    METHODS: set_index_after_delete.

    " Handle events for ALVGrid
    METHODS: do_handle_toolbar
               FOR EVENT toolbar OF cl_gui_alv_grid
               IMPORTING e_object       " type ref to cl_alv_event_toolbar_set
                         e_interactive. " type char01
    METHODS: do_handle_user_command
               FOR EVENT user_command OF cl_gui_alv_grid
               IMPORTING e_ucomm. " type sy-ucomm
    METHODS: do_hotspot_click_command
               FOR EVENT hotspot_click OF cl_gui_alv_grid
               IMPORTING e_row_id     " type  lvc_s_row
                         e_column_id  " type  lvc_s_col
                         es_row_no.   " type  lvc_s_roid
    METHODS: do_double_click_command
               FOR EVENT double_click OF cl_gui_alv_grid
               IMPORTING e_row      " type lvc_s_row optional
                         e_column   " type lvc_s_col optional
                         es_row_no. " type lvc_s_roid optional

    " ALV objects
    DATA: m_grid TYPE REF TO cl_gui_alv_grid,
          m_container TYPE REF TO cl_gui_custom_container.
    " ALV properties
    DATA: m_variant   TYPE disvariant,
          m_layout    TYPE lvc_s_layo,
          m_save      TYPE c VALUE space,
          m_fieldcat  TYPE lvc_t_fcat,
          m_sortcat   TYPE lvc_t_sort,
          m_groupcat  TYPE lvc_t_sgrp.
    " ALV navigation
    DATA: m_index_rows TYPE lvc_t_row,
          m_select_row TYPE lvc_s_row.
    " ALV data
    DATA: m_outtab TYPE REF TO data.

ENDCLASS.                    "lcl_gui_grid_screen  DEFINITIO

*&---------------------------------------------------------------------*
*&  Include           ZCA_GUI_SCREENS
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Разработчик : Андрей Володин
*& Постановщик :
*& Дата начала разработки : 15.12.2008
*& Описание разработки :
*& Запрос ITSM :
*&---------------------------------------------------------------------*
*& Лог изменений
*& Дата      Разработчик   Описание
*&
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*&  Include           ZCA_GUI_SCREENS
*&---------------------------------------------------------------------*

CLASS lcl_gui_utils IMPLEMENTATION.

  METHOD build_dd_fieldcatalog.
*     IMPORTING
*          value(i_program_name) TYPE  sy-repid OPTIONAL
*          value(i_internal_tabname) TYPE slis_tabname OPTIONAL
*          value(i_structure_name) TYPE dd02l-tabname OPTIONAL
*          value(i_client_never_display) TYPE  slis_char_1 DEFAULT 'X'
*          value(i_inclname) TYPE  trdir-name OPTIONAL
*          value(i_bypassing_buffer) TYPE  char01 OPTIONAL
*          value(i_buffer_active) TYPE  char01 OPTIONAL
*        EXPORTING
*          et_fldcat_lvc TYPE  lvc_t_fcat
*        CHANGING
*          itab TYPE STANDARD TABLE
*        EXCEPTIONS
*            inconsistent_interface
*            program_error
*            no_fields
*            it_data_missing

    DATA: lt_fldcat_slis TYPE slis_t_fieldcat_alv.

    CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
      EXPORTING
        i_program_name         = i_program_name
        i_internal_tabname     = i_internal_tabname
        i_structure_name       = i_structure_name
        i_client_never_display = i_client_never_display
        i_inclname             = i_inclname
        i_bypassing_buffer     = i_bypassing_buffer
        i_buffer_active        = i_buffer_active
      CHANGING
        ct_fieldcat            = lt_fldcat_slis
      EXCEPTIONS
        inconsistent_interface = 1
        program_error          = 2
        OTHERS                 = 3.
    IF sy-subrc EQ 1.
      RAISE inconsistent_interface.
    ELSEIF sy-subrc EQ 2.
      RAISE program_error .
    ENDIF.
    IF lt_fldcat_slis[] IS INITIAL.
      RAISE no_fields.
    ENDIF.

    CALL FUNCTION 'LVC_TRANSFER_FROM_SLIS'
      EXPORTING
        it_fieldcat_alv = lt_fldcat_slis[]
      IMPORTING
        et_fieldcat_lvc = et_fldcat_lvc[]
      TABLES
        it_data         = itab[]
      EXCEPTIONS
        it_data_missing = 1
        OTHERS          = 2.
    IF sy-subrc EQ 1.
      RAISE it_data_missing.
    ENDIF.
    IF et_fldcat_lvc[] IS INITIAL.
      RAISE no_fields.
    ENDIF.

  ENDMETHOD.                    "build_dd_fieldcatalog

  METHOD free_and_initial.
    " CHANGING
    "  ch_window  TYPE REF TO lcl_gui_window.

    CHECK ch_window IS NOT INITIAL.
    CALL METHOD ch_window->free( ).
    FREE ch_window.

  ENDMETHOD.                    "free_and_initial

ENDCLASS.                    "lcl_gui_utils IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_gui_application IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_application IMPLEMENTATION.


  METHOD constructor.

    IF o_this IS NOT INITIAL.
      FREE o_this.
    ENDIF.
    o_this = me.

  ENDMETHOD.                    "constructor

  METHOD pbo.
    " importing i_ucomm type syucomm

    DATA l_window TYPE REF TO lcl_gui_window.
    " Последнее значение
    CALL METHOD lcl_gui_application=>pick
      RECEIVING
        r_result  = l_window
      EXCEPTIONS
        ex_empty  = 1
        no_result = 2
        OTHERS    = 3.
    IF sy-subrc EQ 0.
      CALL METHOD l_window->do_pbo
        EXPORTING
          i_ucomm = i_ucomm.
    ENDIF.

  ENDMETHOD.                    "pbo

  METHOD pai.
    " importing i_ucomm type syucomm

    DATA l_window TYPE REF TO lcl_gui_window.
    " Последнее значение
    CALL METHOD lcl_gui_application=>pick
      RECEIVING
        r_result  = l_window
      EXCEPTIONS
        ex_empty  = 1
        no_result = 2
        OTHERS    = 3.
    IF sy-subrc EQ 0.
      CALL METHOD l_window->do_pai
        EXPORTING
          i_ucomm = i_ucomm.
    ENDIF.

  ENDMETHOD.                    "pai

  METHOD user_exit.
    " importing i_ucomm type syucomm

    DATA:
      l_ucomm TYPE syucomm,
      l_window TYPE REF TO lcl_gui_window.

    l_ucomm = i_ucomm.
    " Последнее значение
    CALL METHOD lcl_gui_application=>pick
      RECEIVING
        r_result  = l_window
      EXCEPTIONS
        ex_empty  = 1
        no_result = 2
        OTHERS    = 3.
    IF sy-subrc EQ 0.
      IF l_ucomm EQ 'BACK' OR l_ucomm EQ 'CANCEL'.
        CALL METHOD l_window->do_exit
          CHANGING
            ch_ucomm = l_ucomm.
      ENDIF.
    ENDIF.

    CASE l_ucomm.
      WHEN 'BACK'.
        CALL METHOD lcl_gui_application=>back( ).
      WHEN 'CANCEL'.
        CALL METHOD lcl_gui_application=>exit( ).
    ENDCASE.

  ENDMETHOD.                    "user_exit

  METHOD register.
    " importing i_window type ref to lcl_gui_window

    CALL METHOD lcl_gui_application=>push
      EXPORTING
        i_window = i_window.

  ENDMETHOD.                    "register

  METHOD clear.

    DATA: l_object TYPE REF TO object,
          l_window TYPE REF TO lcl_gui_window.
    LOOP AT o_stack INTO l_object.
      l_window ?= l_object.
      CHECK l_window IS NOT INITIAL.
      CALL METHOD l_window->free.
      FREE l_window.
    ENDLOOP.
    REFRESH o_stack.

  ENDMETHOD.                    "clear

  METHOD push.
    " importing i_window type ref to lcl_gui_window

    " Если стек пуст
    IF LINES( o_stack ) EQ 0.
      APPEND i_window TO o_stack.
      RETURN.
    ENDIF.

    " Если элемент уже в стеке
    DATA: l_tabix  TYPE sytabix,
          l_exists TYPE char1 VALUE IS INITIAL,
          l_object TYPE REF TO object,
          l_window TYPE REF TO lcl_gui_window.
    LOOP AT o_stack INTO l_object.
      l_tabix = sy-tabix.
      l_window ?= l_object.
      CHECK l_window IS NOT INITIAL.
      IF l_window->get_dynnr( ) EQ
         i_window->get_dynnr( ).
        IF l_tabix NE LINES( o_stack ).
          DELETE o_stack INDEX l_tabix.
          APPEND i_window TO o_stack.
          RETURN.
        ENDIF.
      ENDIF.
    ENDLOOP.

    " В любом случае
    APPEND i_window TO o_stack.

  ENDMETHOD.                    "push

  METHOD pick.
    " returning value(r_result) type ref to lcl_gui_window
    " exceptions ex_empty no_result

    DATA: l_tabix TYPE sytabix.
    l_tabix = LINES( o_stack ).

    " Если стек пуст
    IF l_tabix EQ 0.
      RAISE ex_empty.
    ENDIF.

    " Последнее значение
    DATA: l_object TYPE REF TO object.
    READ TABLE o_stack INDEX l_tabix INTO l_object.
    IF sy-subrc NE 0.
      RAISE no_result.
    ENDIF.
    r_result ?= l_object.
    IF r_result IS INITIAL.
      RAISE no_result.
    ENDIF.

  ENDMETHOD.                    "pick

  METHOD pop.
    " returning value(r_result) type ref to lcl_gui_window
    " exceptions ex_empty no_result

    DATA: l_tabix TYPE sytabix.
    l_tabix = LINES( o_stack ).

    " Если стек пуст
    IF l_tabix EQ 0.
      RAISE ex_empty.
    ENDIF.

    " Последнее значение
    CALL METHOD lcl_gui_application=>pick
      RECEIVING
        r_result  = r_result
      EXCEPTIONS
        ex_empty  = 1
        no_result = 2
        OTHERS    = 3.
    CASE sy-subrc.
      WHEN 0.
        DELETE o_stack INDEX l_tabix.
      WHEN 1.
        RAISE ex_empty.
      WHEN 2.
        RAISE no_result.
    ENDCASE.

  ENDMETHOD.                    "pop

  METHOD back.

    DATA l_window TYPE REF TO lcl_gui_window.
    CALL METHOD lcl_gui_application=>pop
      RECEIVING
        r_result  = l_window
      EXCEPTIONS
        ex_empty  = 1
        no_result = 2
        OTHERS    = 3.
    IF sy-subrc EQ 0.
      CALL METHOD l_window->free( ).
    ENDIF.

    LEAVE TO SCREEN 0.

  ENDMETHOD.                    "back

  METHOD exit.

    " Очистить стек окон
    CALL METHOD lcl_gui_application=>clear.
    " Выход
    LEAVE PROGRAM.

  ENDMETHOD.                    "exit

ENDCLASS.                    "lcl_gui_application IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_gui_window IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_window IMPLEMENTATION.

  METHOD get_window.
    " importing value(i_class) type string
    "           value(i_dynnr) type sydynnr
    " returning value(r_result) type ref to lcl_gui_window

    DATA:
      l_this TYPE REF TO lcl_gui_window.
    TRY.
        CREATE OBJECT l_this
          TYPE
            (i_class)
          EXPORTING
            i_dynnr   = i_dynnr.
        IF l_this IS NOT INITIAL.
          r_result = l_this.
        ELSE.
          FREE l_this.
        ENDIF.
      CATCH cx_sy_create_object_error.
        MESSAGE 'Create object error'
          TYPE 'S' DISPLAY LIKE 'E'.
    ENDTRY.

  ENDMETHOD.                    "get_window

  METHOD constructor.
    " importing i_dynnr type sydynnr

    m_dynnr = i_dynnr.

  ENDMETHOD.                    "constructor

  METHOD free.
  ENDMETHOD.                    "free

  METHOD do_pbo.
    " importing i_ucomm type syucomm
  ENDMETHOD.                    "do_pbo

  METHOD do_pai.
    " importing i_ucomm type syucomm
  ENDMETHOD.                    "do_pai

  METHOD do_exit.
    " importing i_ucomm type syucomm
  ENDMETHOD.                    "do_exit

  METHOD get_dynnr.
    " returning value(r_result) type sydynnr

    r_result = m_dynnr.

  ENDMETHOD.                    "get_dynnr

ENDCLASS.                    "lcl_gui_window IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_gui_screen IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_screen IMPLEMENTATION.

  METHOD get_screen.
    " importing value(i_class) type string
    "           value(i_dynnr) type sydynnr
    " returning value(r_result) type ref to lif_gui_screen

    DATA: l_window TYPE REF TO lcl_gui_window,
          l_screen TYPE REF TO lcl_gui_screen.
    TRY .
        CALL METHOD lcl_gui_window=>get_window
          EXPORTING
            i_class  = i_class
            i_dynnr  = i_dynnr
          RECEIVING
            r_result = l_window.
        IF l_window IS NOT INITIAL.
          l_screen ?= l_window.
        ENDIF.
        IF l_screen IS NOT INITIAL.
          r_result = l_screen.
        ENDIF.
      CATCH cx_root.
        FREE l_screen.
    ENDTRY.

  ENDMETHOD.                    "get_screen

  METHOD free.
  ENDMETHOD.                    "free


  METHOD do_pbo.
    " importing i_ucomm type syucomm

    CALL METHOD super->do_pbo
      EXPORTING
        i_ucomm = i_ucomm.

    " Инициализировать экран
    CALL METHOD me->do_init_screen.

  ENDMETHOD.                    "do_pbo

  METHOD do_pai.
    " importing i_ucomm type syucomm

    CALL METHOD super->do_pai
      EXPORTING
        i_ucomm = i_ucomm.

  ENDMETHOD.                    "do_pai

  METHOD do_call_screen.

    DATA l_dynnr TYPE sydynnr.
    " Номер экрана
    CALL METHOD me->get_dynnr
      RECEIVING
        r_result = l_dynnr.
    " Зарегистрировать
    CALL METHOD lcl_gui_application=>register
      EXPORTING
        i_window = me.
    " Вызов экрана
    CALL SCREEN l_dynnr.

  ENDMETHOD.                    "do_call_screen

  METHOD do_init_screen.
  ENDMETHOD.                    "do_init_screen


  METHOD lif_gui_screen~call_screen.

    " Отобразить экран
    CALL METHOD me->do_call_screen.

  ENDMETHOD.                    "lif_gui_screen~call_screen

ENDCLASS.                    "lcl_gui_screen IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_gui_dialog IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_dialog IMPLEMENTATION.

  METHOD get_dialog.
    " importing value(i_class) type string
    "           value(i_dynnr) type sydynnr
    "                 i_screen type ref to lcl_gui_screen
    "                      i_x type i optional
    "                      i_y type i optional
    "                      i_m type i optional
    "                      i_n type i optional
    " returning value(r_result) type ref to lif_gui_dialog.

    DATA: l_window TYPE REF TO lcl_gui_window,
          l_dialog TYPE REF TO lcl_gui_dialog.
    TRY .
        CALL METHOD lcl_gui_window=>get_window
          EXPORTING
            i_class  = i_class
            i_dynnr  = i_dynnr
          RECEIVING
            r_result = l_window.
        IF l_window IS NOT INITIAL.
          l_dialog ?= l_window.
        ENDIF.
        IF l_dialog IS NOT INITIAL.
          CALL METHOD l_dialog->set_screen
            EXPORTING
              i_screen = i_screen.
          CALL METHOD l_dialog->set_bounds
            EXPORTING
              i_x = i_x
              i_y = i_y
              i_m = i_m
              i_n = i_n.
          r_result = l_dialog.
        ENDIF.
      CATCH cx_root.
        FREE l_dialog.
    ENDTRY.

  ENDMETHOD.                    "get_dialog

  METHOD constructor.
    " importing i_dynnr  type sydynnr
    "           i_screen type ref to lcl_gui_screen
    "                           optional
    "                i_x type i optional
    "                i_y type i optional
    "                i_m type i optional
    "                i_n type i optional

    " Базовый метод
    CALL METHOD super->constructor
      EXPORTING
        i_dynnr = i_dynnr.

    " Вызвавший экран
    me->m_screen = i_screen.
    " Координаты
    me->m_x = i_x.
    me->m_y = i_y.
    me->m_m = i_m.
    me->m_n = i_n.

  ENDMETHOD.                    "constructor

  METHOD do_pbo.
    " importing i_ucomm type syucomm

    CALL METHOD super->do_pbo
      EXPORTING
        i_ucomm = i_ucomm.

  ENDMETHOD.                    "do_pbo

  METHOD do_pai.
    " importing i_ucomm type syucomm

    CALL METHOD super->do_pai
      EXPORTING
        i_ucomm = i_ucomm.

    CASE i_ucomm.
      WHEN c_applyfunc.
        CALL METHOD me->do_apply_record( ).
      WHEN c_cancelfunc.
        CALL METHOD me->do_cancel_record( ).
    ENDCASE.

  ENDMETHOD.                    "do_pai

  METHOD set_screen.
    " importing i_screen type ref to lcl_gui_screen

    IF i_screen IS NOT INITIAL.
      m_screen = i_screen.
    ENDIF.

  ENDMETHOD.                    "set_screen

  METHOD get_screen.
    " returning value(r_result) type ref to lcl_gui_screen

    r_result = m_screen.

  ENDMETHOD.                    "get_screen

  METHOD set_bounds.
    " importing i_x type i
    "           i_y type i
    "           i_m type i optional
    "           i_n type i optional

    IF i_x IS NOT INITIAL. m_x = i_x. ENDIF.
    IF i_y IS NOT INITIAL. m_y = i_y. ENDIF.
    IF i_m IS NOT INITIAL. m_m = i_m. ENDIF.
    IF i_n IS NOT INITIAL. m_n = i_n. ENDIF.

  ENDMETHOD.                    "set_bounds

  METHOD get_bounds.
    " exporting e_x type i
    "           e_y type i
    "           e_m type i
    "           e_n type i

    e_x = m_x.
    e_y = m_y.
    e_m = m_m.
    e_n = m_n.

  ENDMETHOD.                    "get_bounds

  METHOD do_call_dialog.
    " IMPORTING i_action TYPE i OPTIONAL
    "                i_x TYPE i OPTIONAL
    "                i_y TYPE i OPTIONAL
    "                i_m TYPE i OPTIONAL
    "                i_n TYPE i OPTIONAL

    DATA l_action TYPE i.
    IF i_action IS INITIAL.
      l_action = c_browse.
    ELSE.
      l_action = i_action.
    ENDIF.
    CALL METHOD me->do_init_action( l_action ).

    IF i_x IS NOT INITIAL. m_x = i_x. ENDIF.
    IF i_y IS NOT INITIAL. m_y = i_y. ENDIF.
    IF i_m IS NOT INITIAL. m_m = i_m. ENDIF.
    IF i_n IS NOT INITIAL. m_n = i_n. ENDIF.

    DATA l_dynnr TYPE sydynnr.
    " Номер экрана
    CALL METHOD me->get_dynnr
      RECEIVING
        r_result = l_dynnr.

    " Зарегистрировать
    CALL METHOD lcl_gui_application=>register
      EXPORTING
        i_window = me.

    IF m_m IS INITIAL OR m_n IS INITIAL.
      CALL SCREEN l_dynnr STARTING AT m_x m_y.
    ELSE.
      CALL SCREEN l_dynnr STARTING AT m_x m_y
                            ENDING AT m_m m_n.
    ENDIF.

  ENDMETHOD.                    "do_call_dialog

  METHOD do_read_action.
    " RETURNING value(r_result) TYPE i

    r_result = m_action.

  ENDMETHOD.                    "do_read_action

  METHOD do_init_action.
    " IMPORTING value(i_action) TYPE i

    m_action = i_action.

  ENDMETHOD.                    "do_init_action

  METHOD do_apply_record.

    CALL METHOD lcl_gui_application=>back( ).

  ENDMETHOD.                    "do_apply_record

  METHOD do_cancel_record.

    CALL METHOD lcl_gui_application=>back( ).

  ENDMETHOD.                    "do_cancel_record

  METHOD lif_gui_dialog~call_dialog.
    " IMPORTING i_action TYPE i OPTIONAL
    "                i_x TYPE i OPTIONAL
    "                i_y TYPE i OPTIONAL
    "                i_m TYPE i OPTIONAL
    "                i_n TYPE i OPTIONAL

    CALL METHOD me->do_call_dialog
      EXPORTING
        i_action = i_action
        i_x      = i_x
        i_y      = i_y
        i_m      = i_m
        i_n      = i_n.

  ENDMETHOD.                    "lif_gui_dialog~call_dialog

ENDCLASS.                    "lcl_gui_dialog IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_gui_subscreen IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_subscreen IMPLEMENTATION.

  METHOD pbo.
    " IMPORTING i_ucomm TYPE syucomm

    IF o_this IS NOT INITIAL.
      CALL METHOD o_this->do_pbo( i_ucomm ).
    ENDIF.

  ENDMETHOD.                    "pbo

  METHOD pai.
    " IMPORTING i_ucomm TYPE syucomm

    IF o_this IS NOT INITIAL.
      CALL METHOD o_this->do_pai( i_ucomm ).
    ENDIF.

  ENDMETHOD.                    "pai

  METHOD constructor.
    " IMPORTING i_dynnr TYPE sydynnr
    "           i_owner TYPE REF TO lcl_gui_window

    CALL METHOD super->constructor
      EXPORTING
        i_dynnr = i_dynnr.
    " Одиночка
    o_this = me.
    " Владелец
    m_owner = i_owner.

  ENDMETHOD.                    "constructor

  METHOD do_pbo.
    " importing i_ucomm type syucomm

    CALL METHOD super->do_pbo( i_ucomm ).
    " Инициализация
    CALL METHOD me->do_init_subscreen.

  ENDMETHOD.                    "do_pbo

  METHOD do_pai.
    " importing i_ucomm type syucomm

    CALL METHOD super->do_pai( i_ucomm ).

  ENDMETHOD.                    "do_pai

  METHOD do_init_subscreen.

  ENDMETHOD.                    "do_init_subscreen

ENDCLASS.                    "lcl_gui_subscreen IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_gui_view_screen IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_view_screen IMPLEMENTATION.

  METHOD lif_gui_view_screen~save_record.

    CALL METHOD me->do_save_record.

  ENDMETHOD.                    "lif_gui_screen~save_record

  METHOD lif_gui_view_screen~next_record.

    CALL METHOD me->do_next_record.

  ENDMETHOD.                    "lif_gui_screen~next_record

  METHOD lif_gui_view_screen~prev_record.

    CALL METHOD me->do_prev_record.

  ENDMETHOD.                    "lif_gui_screen~prev_record

  METHOD do_pbo.
    " importing i_ucomm type syucomm

    CALL METHOD super->do_pbo
      EXPORTING
        i_ucomm = i_ucomm.

    "set pf-status ''.
    "set titlebar ''.

  ENDMETHOD.                    "do_pbo


  METHOD do_pai.
    " importing i_ucomm type syucomm

    CASE i_ucomm.
      WHEN 'BROWSE'.
        CALL METHOD me->do_browse_dialog.
      WHEN 'CREATE'.
        CALL METHOD me->do_create_dialog.
      WHEN 'UPDATE'.
        CALL METHOD me->do_update_dialog.
      WHEN 'DELETE'.
        CALL METHOD me->do_delete_dialog.
    ENDCASE.

    CALL METHOD super->do_pai
      EXPORTING
        i_ucomm = i_ucomm.

  ENDMETHOD.                    "do_pai

  METHOD do_active_dialog.

    IF m_dialog IS NOT INITIAL.
      FREE m_dialog.
    ENDIF.

  ENDMETHOD.                    "do_active_dialog

  METHOD do_browse_dialog.

    DATA l_record TYPE REF TO data.
    CALL METHOD me->do_read_record
      RECEIVING
        r_result = l_record.
    CHECK l_record IS NOT INITIAL.

    CALL METHOD me->do_active_dialog.
    CHECK m_dialog IS NOT INITIAL.
    CALL METHOD m_dialog->init_record
      EXPORTING
        i_record = l_record.
    DATA l_dialog TYPE REF TO lcl_gui_dialog.
    l_dialog ?= m_dialog.
    CHECK l_dialog IS NOT INITIAL.
    CALL METHOD l_dialog->call_dialog
      EXPORTING
        i_action = me->c_browse.

  ENDMETHOD.                    "do_browse_dialog

  METHOD do_create_dialog.

    DATA l_access TYPE char1.
    CALL METHOD me->do_check_role
      EXPORTING
        i_action = me->c_create
      RECEIVING
        r_result = l_access.
    CHECK l_access IS NOT INITIAL.

    DATA l_record TYPE REF TO data.
    CALL METHOD me->get_structure_data
      RECEIVING
        r_result = l_record.
    CHECK l_record IS NOT INITIAL.

    CALL METHOD me->do_active_dialog.
    CHECK m_dialog IS NOT INITIAL.
    CALL METHOD m_dialog->init_record
      EXPORTING
        i_record = l_record.
    DATA l_dialog TYPE REF TO lcl_gui_dialog.
    l_dialog ?= m_dialog.
    CHECK l_dialog IS NOT INITIAL.
    CALL METHOD l_dialog->call_dialog
      EXPORTING
        i_action = me->c_create.

  ENDMETHOD.                    "do_create_dialog

  METHOD do_update_dialog.

    DATA l_access TYPE char1.
    CALL METHOD me->do_check_role
      EXPORTING
        i_action = me->c_update
      RECEIVING
        r_result = l_access.
    CHECK l_access IS NOT INITIAL.

    DATA l_record TYPE REF TO data.
    CALL METHOD me->do_read_record
      RECEIVING
        r_result = l_record.
    CHECK l_record IS NOT INITIAL.

    CALL METHOD me->do_active_dialog.
    CHECK m_dialog IS NOT INITIAL.
    CALL METHOD m_dialog->init_record
      EXPORTING
        i_record = l_record.
    DATA l_dialog TYPE REF TO lcl_gui_dialog.
    l_dialog ?= m_dialog.
    CHECK l_dialog IS NOT INITIAL.
    CALL METHOD l_dialog->call_dialog
      EXPORTING
        i_action = me->c_update.

  ENDMETHOD.                    "do_update_dialog

  METHOD do_delete_dialog.

    DATA l_access TYPE char1.
    CALL METHOD me->do_check_role
      EXPORTING
        i_action = me->c_delete
      RECEIVING
        r_result = l_access.
    CHECK l_access IS NOT INITIAL.

    DATA l_record TYPE REF TO data.
    CALL METHOD me->do_read_record
      RECEIVING
        r_result = l_record.
    CHECK l_record IS NOT INITIAL.

    DATA l_result TYPE char1 VALUE IS INITIAL.

    CALL FUNCTION 'POPUP_TO_CONFIRM'
      EXPORTING
        text_question  = 'Удалить запись?'
      IMPORTING
        answer         = l_result
      EXCEPTIONS
        text_not_found = 1
        OTHERS         = 2.
    CHECK l_result EQ '1'.

    CALL METHOD me->do_delete_record
      EXPORTING
        i_record  = l_record
      EXCEPTIONS
        no_result = 1
        OTHERS    = 2.

  ENDMETHOD.                    "do_delete_dialog

  METHOD do_create_record.
    " importing value(i_record) type ref to data
    " exceptions no_result

    CHECK i_record IS NOT INITIAL.
    TRY .
        CALL METHOD me->do_create_by_id
          EXPORTING
            i_record  = i_record
          EXCEPTIONS
            no_result = 1
            OTHERS    = 2.
        IF sy-subrc EQ 0.
          CALL METHOD me->do_init_record
            EXPORTING
              i_action = c_create
              i_record = i_record.
        ELSE.
          RAISE no_result.
        ENDIF.
      CATCH cx_root.
        RAISE no_result.
    ENDTRY.

  ENDMETHOD.                    "do_create_record

  METHOD do_update_record.
    " importing value(i_record) type ref to data
    " exceptions no_result

    CHECK i_record IS NOT INITIAL.
    TRY .
        CALL METHOD me->do_update_by_id
          EXPORTING
            i_record  = i_record
          EXCEPTIONS
            no_result = 1
            OTHERS    = 2.
        IF sy-subrc EQ 0.
          CALL METHOD me->do_init_record
            EXPORTING
              i_action = c_update
              i_record = i_record.
        ELSE.
          RAISE no_result.
        ENDIF.
      CATCH cx_root.
        RAISE no_result.
    ENDTRY.

  ENDMETHOD.                    "do_edit_record

  METHOD do_delete_record.
    " importing value(i_record) type ref to data
    " exceptions no_result

    CHECK i_record IS NOT INITIAL.
    TRY.
        CALL METHOD me->do_delete_by_id
          EXPORTING
            i_record  = i_record
          EXCEPTIONS
            no_result = 1
            OTHERS    = 2.
        IF sy-subrc EQ 0.
          CALL METHOD me->do_init_record
            EXPORTING
              i_action = c_delete
              i_record = i_record.
        ELSE.
          RAISE no_result.
        ENDIF.
      CATCH cx_root.
        RAISE no_result.
    ENDTRY.

  ENDMETHOD.                    "do_delete_record

  METHOD do_save_record.

    DATA: l_action TYPE i,
          l_record TYPE REF TO data.

    CALL METHOD me->get_structure_data
      RECEIVING
        r_result = l_record.
    CHECK l_record IS NOT INITIAL.

    CALL METHOD m_dialog->read_record
      CHANGING
        i_record = l_record.

    CALL METHOD m_dialog->read_action
      RECEIVING
        r_result = l_action.

    IF l_action EQ me->c_create.
      " Проверка
      CALL METHOD me->do_check_record
        EXPORTING
          i_action = l_action
          i_record = l_record
        RECEIVING
          r_result = l_action.
    ENDIF.

    CASE l_action.
      WHEN me->c_create.
        CALL METHOD me->do_create_record
          EXPORTING
            i_record  = l_record
          EXCEPTIONS
            no_result = 1
            OTHERS    = 2.
      WHEN me->c_update.
        CALL METHOD me->do_update_record
          EXPORTING
            i_record  = l_record
          EXCEPTIONS
            no_result = 1
            OTHERS    = 2.
      WHEN OTHERS.
    ENDCASE.

    IF sy-subrc EQ 0 AND ( l_action EQ c_create OR l_action EQ c_update ).
      MESSAGE 'Данные успешно сохранены' TYPE 'S'.
    ELSE.
      MESSAGE 'Произошла ошибка при сохранении данных'
        TYPE 'S' DISPLAY LIKE 'E'.
    ENDIF.

    FREE l_record.

  ENDMETHOD.                    "do_save_record

  METHOD do_next_record.
    " returning value(r_result) type ref to data
  ENDMETHOD.                    "do_next_record

  METHOD do_prev_record.
    " returning value(r_result) type ref to data
  ENDMETHOD.                    "do_prev_record

  METHOD do_read_record.
    " returning value(r_result) type ref to data
  ENDMETHOD.                    "do_read_record

  METHOD do_init_record.
    " importing value(i_action) type i
    " value(i_record) type ref to data
  ENDMETHOD.                    "do_init_record

  METHOD do_check_record.
    " importing value(i_action) type i
    "           value(i_record) type ref to data
    " returning value(r_result) type i
  ENDMETHOD.                    "do_check_record

  METHOD do_check_role.
    " importing value(i_action) type i
    " returning value(r_result) type char1
  ENDMETHOD.                    "do_check_role

  METHOD do_select_by_id.
    " importing i_record type ref to data
    " exceptions no_result
  ENDMETHOD.                    "do_select_by_id

  METHOD do_create_by_id.
    " importing i_record type ref to data
    " exceptions no_result
  ENDMETHOD.                    "do_create_by_id

  METHOD do_update_by_id.
    " importing i_record type ref to data
    " exceptions no_result
  ENDMETHOD.                    "do_update_by_id

  METHOD do_delete_by_id.
    " importing i_record type ref to data
    " exceptions no_result
  ENDMETHOD.                    "do_delete_by_id

ENDCLASS.                    "lcl_gui_view_screen IMPLEMENTATION


*----------------------------------------------------------------------*
*       CLASS lcl_gui_view_dialog IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_view_dialog IMPLEMENTATION.

  METHOD do_pbo.
    " importing i_ucomm type syucomm

    CALL METHOD super->do_pbo
      EXPORTING
        i_ucomm = i_ucomm.

  ENDMETHOD.                    "do_pbo

  METHOD do_pai.
    " importing i_ucomm type syucomm

    CALL METHOD super->do_pai
      EXPORTING
        i_ucomm = i_ucomm.

    CASE i_ucomm.
      WHEN 'NEXT'.
        CALL METHOD me->do_next_record.
      WHEN 'PREV'.
        CALL METHOD me->do_prev_record.
    ENDCASE.

  ENDMETHOD.                    "do_pai

  METHOD do_apply_record.

    CALL METHOD me->do_save_record( ).

  ENDMETHOD.                    "do_apply_record

  METHOD do_read_record.
    " changing i_record type ref to data
  ENDMETHOD.                    "do_read_record

  METHOD do_init_record.
    " importing i_record type ref to data
  ENDMETHOD.                    "do_init_record

  METHOD do_save_record.

    CASE m_action.
      WHEN c_create OR c_update.
        DATA l_screen TYPE REF TO lcl_gui_view_screen.
        l_screen ?= m_screen.
        IF l_screen IS NOT INITIAL.
          CALL METHOD l_screen->save_record.
        ENDIF.
      WHEN c_cancel OR c_browse OR c_delete.
        CALL METHOD lcl_gui_application=>back( ).
      WHEN OTHERS.
        MESSAGE 'Неизвестный режим' TYPE 'S'.
    ENDCASE.

  ENDMETHOD.                    "do_save_record

  METHOD do_next_record.

    IF m_screen IS NOT INITIAL.
      IF m_action EQ c_create.
        MESSAGE 'В этом режиме функция недоступна' TYPE 'S'.
      ELSE.
        DATA l_screen TYPE REF TO lcl_gui_view_screen.
        l_screen ?= m_screen.
        IF l_screen IS NOT INITIAL.
          CALL METHOD l_screen->next_record.
        ENDIF.
      ENDIF.
    ENDIF.

  ENDMETHOD.                    "do_next_record

  METHOD do_prev_record.

    IF m_screen IS NOT INITIAL.
      IF m_action EQ c_create.
        MESSAGE 'В этом режиме функция недоступна' TYPE 'S'.
      ELSE.
        DATA l_screen TYPE REF TO lcl_gui_view_screen.
        l_screen ?= m_screen.
        IF l_screen IS NOT INITIAL.
          CALL METHOD l_screen->prev_record.
        ENDIF.
      ENDIF.
    ENDIF.

  ENDMETHOD.                    "do_prev_record

  METHOD lif_gui_view_dialog~init_record.
    " importing i_record type ref to data

    CALL METHOD me->do_init_record
      EXPORTING
        i_record = i_record.

  ENDMETHOD.                    "lif_gui_dialog~init_record

  METHOD lif_gui_view_dialog~read_record.
    " changing i_record type ref to data

    CALL METHOD me->do_read_record
      CHANGING
        i_record = i_record.

  ENDMETHOD.                    "lif_gui_dialog~read_record

  METHOD lif_gui_view_dialog~read_action.
    " returning value(r_result) type i

    r_result = me->do_read_action( ).

  ENDMETHOD.                    "lif_gui_dialog~read_action

  METHOD lif_gui_view_dialog~init_action.
    "importing value(i_action) type i

    CALL METHOD me->do_init_action( i_action ).

  ENDMETHOD.                    "lif_gui_dialog~init_action

ENDCLASS.                    "lcl_gui_view_dialog IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_gui_view_subscreen IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_view_subscreen IMPLEMENTATION.

  METHOD get_mode.
    " RETURNING value(result) TYPE i

    result = m_mode.

  ENDMETHOD.                    "get_mode

  METHOD set_mode.
    " IMPORTING value(i_mode) TYPE i

    m_mode = i_mode.

  ENDMETHOD.                    "set_mode

ENDCLASS.                    "lcl_gui_view_subscreen IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_gui_grid_screen IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_gui_grid_screen IMPLEMENTATION.

  METHOD free.

    FREE: m_grid, m_container.
    CALL METHOD super->free.
    CALL METHOD cl_gui_cfw=>flush.

  ENDMETHOD.                    "free

  METHOD do_init_screen.

    IF m_grid IS INITIAL.
      " Create GUI objects
      DATA l_container_name TYPE c LENGTH 32.
      CALL METHOD me->get_container_name
        RECEIVING
          r_result = l_container_name.
      CONDENSE l_container_name NO-GAPS.
      CHECK l_container_name IS NOT INITIAL.

      " Create objects
      CREATE OBJECT m_container
        EXPORTING
          container_name = l_container_name.
      CREATE OBJECT m_grid
        EXPORTING
          i_parent = m_container.

      " Fill structure for IS_VARIANT
      CALL METHOD me->do_init_variant.
      " Fill structure for IS_LAYOUT
      CALL METHOD me->do_init_layout.
      " Build field catalog
      CALL METHOD me->do_init_fields.
      " Build special groups
      CALL METHOD me->do_init_groups.
      " Build sort catalog
      CALL METHOD me->do_init_sorted.
      " Load data
      CALL METHOD me->do_init_outtab.

      " Set handlers
      CALL METHOD me->set_alvgrid_handlers.
      " Set receiver for edit
      CALL METHOD me->set_alvgrid_edit_event.
    ELSE.
      CALL METHOD m_grid->refresh_table_display.
    ENDIF.

    CALL METHOD cl_gui_cfw=>flush.

  ENDMETHOD.                    "do_init_screen

  METHOD do_init_variant.

    m_variant-report = sy-repid.

  ENDMETHOD.                    "do_init_variant

  METHOD do_init_layout.

    m_layout-no_rowins  = 'X'.
    m_layout-edit       = space.
    m_layout-sel_mode   = 'B'.
    m_layout-zebra      = 'X'.
    m_layout-smalltitle = 'X'.
    m_layout-grid_title = me->get_alvgrid_title( ).

  ENDMETHOD.                    "do_init_layout

  METHOD do_init_fields.

    DATA: fieldcat_wa TYPE lvc_s_fcat,
          l_struct_name TYPE dd02l-tabname.

    CALL METHOD me->get_structure_name
      RECEIVING
        r_result = l_struct_name.
    CONDENSE l_struct_name NO-GAPS.
    CHECK l_struct_name IS NOT INITIAL.

    CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
      EXPORTING
        i_structure_name       = l_struct_name
      CHANGING
        ct_fieldcat            = m_fieldcat
      EXCEPTIONS
        inconsistent_interface = 1
        program_error          = 2
        OTHERS                 = 3.

  ENDMETHOD.                    "do_init_fields

  METHOD do_init_groups.
  ENDMETHOD.                    "do_init_groups

  METHOD do_init_sorted.
  ENDMETHOD.                    "do_init_sorted

  METHOD do_init_outtab.

    CHECK m_outtab IS NOT INITIAL.

    DATA l_struct_name TYPE dd02l-tabname.
    CALL METHOD me->get_structure_name
      RECEIVING
        r_result = l_struct_name.
    CONDENSE l_struct_name NO-GAPS.
    CHECK l_struct_name IS NOT INITIAL.

    FIELD-SYMBOLS <outtab> TYPE STANDARD TABLE.
    ASSIGN m_outtab->* TO <outtab>.
    CHECK <outtab> IS ASSIGNED.

    TRY.
        CALL METHOD m_grid->set_table_for_first_display
          EXPORTING
            i_structure_name              = l_struct_name
            is_variant                    = m_variant
            i_save                        = m_save
            is_layout                     = m_layout
            it_special_groups             = m_groupcat
          CHANGING
            it_outtab                     = <outtab>
            it_fieldcatalog               = m_fieldcat
            it_sort                       = m_sortcat
          EXCEPTIONS
            invalid_parameter_combination = 1
            program_error                 = 2
            too_many_lines                = 3
            OTHERS                        = 4.
        IF sy-subrc <> 0.
          MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
                     WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
        ENDIF.

        CALL METHOD m_grid->set_toolbar_interactive.

        CHECK LINES( <outtab> ) GT 0.
        m_select_row-index = 1.
        APPEND m_select_row TO m_index_rows.
        CALL METHOD me->set_selected_rows
          EXCEPTIONS
            no_rows = 1
            OTHERS  = 2.
      CATCH cx_root.
    ENDTRY.

  ENDMETHOD.                    "do_init_outtab

  METHOD do_next_record.
    " returning value(r_result) type ref to data

    CHECK m_outtab IS NOT INITIAL.
    CHECK m_dialog IS NOT INITIAL.

    FIELD-SYMBOLS <outtab> TYPE STANDARD TABLE.
    ASSIGN m_outtab->* TO <outtab>.

    CHECK LINES( <outtab> ) GT 0.

    FIELD-SYMBOLS <select> TYPE lvc_s_row.
    READ TABLE m_index_rows INDEX 1 ASSIGNING <select>.

    CHECK sy-subrc EQ 0.

    IF <select>-index IS INITIAL OR <select>-index EQ 1.
      <select>-index = LINES( <outtab> ).
    ELSE.
      SUBTRACT 1 FROM <select>-index.
    ENDIF.

    MODIFY m_index_rows INDEX 1 FROM <select>.

    CALL METHOD me->set_selected_rows
      EXCEPTIONS
        no_rows = 1
        OTHERS  = 2.

    CHECK sy-subrc EQ 0.

    DATA: l_record TYPE REF TO data.

    CALL METHOD me->do_read_record
      RECEIVING
        r_result = r_result.

    CALL METHOD m_dialog->init_record
      EXPORTING
        i_record = r_result.

  ENDMETHOD.                    "do_next_record

  METHOD do_prev_record.
    " returning value(r_result) type ref to data

    CHECK m_outtab IS NOT INITIAL.
    CHECK m_dialog IS NOT INITIAL.

    FIELD-SYMBOLS <outtab> TYPE STANDARD TABLE.
    ASSIGN m_outtab->* TO <outtab>.

    CHECK LINES( <outtab> ) GT 0.

    FIELD-SYMBOLS <select> TYPE lvc_s_row.
    READ TABLE m_index_rows INDEX 1 ASSIGNING <select>.

    CHECK sy-subrc EQ 0.

    IF <select>-index IS INITIAL.
      <select>-index = 1.
    ELSEIF <select>-index EQ LINES( <outtab> ).
      <select>-index = 1.
    ELSEIF <select>-index LT LINES( <outtab> ).
      ADD 1 TO <select>-index.
    ENDIF.

    MODIFY m_index_rows INDEX 1 FROM <select>.

    CALL METHOD me->set_selected_rows
      EXCEPTIONS
        no_rows = 1
        OTHERS  = 2.

    CHECK sy-subrc EQ 0.

    CALL METHOD me->do_read_record
      RECEIVING
        r_result = r_result.

    CALL METHOD m_dialog->init_record
      EXPORTING
        i_record = r_result.

  ENDMETHOD.                    "do_prev_record

  METHOD do_read_record.
    " returning value(r_result) type ref to data

    CALL METHOD me->get_selected_rows
      EXCEPTIONS
        no_rows = 1
        OTHERS  = 2.
    CHECK sy-subrc EQ 0.

    READ TABLE m_index_rows
      INDEX 1 INTO m_select_row.
    CHECK sy-subrc EQ 0.

    DATA lv_index TYPE i.
    lv_index = m_select_row-index.
    CHECK lv_index IS NOT INITIAL.

    FIELD-SYMBOLS <outtab> TYPE STANDARD TABLE.
    ASSIGN m_outtab->* TO <outtab>.

    READ TABLE <outtab> INDEX lv_index
      REFERENCE INTO r_result.

  ENDMETHOD.                    "do_init_record

  METHOD do_init_record.
    "importing value(i_action) type i
    "          value(i_record) type ref to data

    CHECK i_record IS NOT INITIAL.
    FIELD-SYMBOLS <record> TYPE data.
    ASSIGN i_record->* TO <record>.

    FIELD-SYMBOLS <outtab> TYPE STANDARD TABLE.
    ASSIGN m_outtab->* TO <outtab>.

    CASE i_action.
      WHEN me->c_create.
        CALL METHOD me->set_index_before_create.
        APPEND <record> TO <outtab>.
      WHEN me->c_update.
        REFRESH m_index_rows.
        APPEND m_select_row TO m_index_rows.
        MODIFY <outtab> INDEX m_select_row-index FROM <record>.
      WHEN me->c_delete.
        DELETE <outtab> INDEX m_select_row-index.
        CALL METHOD me->set_index_after_delete.
    ENDCASE.

    CALL METHOD m_grid->refresh_table_display.

    CALL METHOD me->set_selected_rows
      EXCEPTIONS
        no_rows = 1
        OTHERS  = 2.

  ENDMETHOD.                    "do_save_record

  METHOD get_selected_rows.
    " exceptions no_rows

    CALL METHOD m_grid->get_selected_rows
      IMPORTING
        et_index_rows = m_index_rows.
    IF LINES( m_index_rows ) GT 0.
      READ TABLE m_index_rows INDEX 1 INTO m_select_row.
      IF sy-subrc NE 0.
        RAISE no_rows.
      ENDIF.
    ELSE.
      RAISE no_rows.
    ENDIF.

  ENDMETHOD.                    "get_selected_rows

  METHOD set_selected_rows.
    " exceptions no_rows

    IF LINES( m_index_rows ) GT 0.
      CALL METHOD m_grid->set_selected_rows
        EXPORTING
          it_index_rows = m_index_rows.
    ELSE.
      RAISE no_rows.
    ENDIF.

  ENDMETHOD.                    "set_selected_rows

  METHOD set_alvgrid_handlers.

    SET HANDLER me->do_handle_toolbar
      FOR m_grid.
    SET HANDLER me->do_handle_user_command
      FOR m_grid.
    SET HANDLER me->do_double_click_command
      FOR m_grid.
    SET HANDLER me->do_hotspot_click_command
      FOR m_grid.

  ENDMETHOD.                    "set_alvgrid_handlers

  METHOD set_alvgrid_edit_event.

    IF m_layout-edit NE space.
      CALL METHOD m_grid->register_edit_event
        EXPORTING
          i_event_id = cl_gui_alv_grid=>mc_evt_modified.
    ENDIF.

  ENDMETHOD.                    "set_alvgrid_edit_event

  METHOD set_index_before_create.

    FIELD-SYMBOLS <outtab> TYPE STANDARD TABLE.
    ASSIGN m_outtab->* TO <outtab>.

    DATA l_index TYPE i.
    l_index = LINES( <outtab> ) + 1.
    REFRESH m_index_rows.
    m_select_row-index = l_index.
    APPEND m_select_row TO m_index_rows.

  ENDMETHOD.                    "set_index_before_create

  METHOD set_index_after_delete.

    FIELD-SYMBOLS <outtab> TYPE STANDARD TABLE.
    ASSIGN m_outtab->* TO <outtab>.

    DATA l_count TYPE i.
    l_count = LINES( <outtab> ).

    REFRESH m_index_rows.
    IF l_count EQ 0.
      CLEAR m_select_row-index.
    ELSEIF m_select_row-index GT l_count.
      m_select_row-index = l_count.
    ENDIF.
    CHECK m_select_row-index IS NOT INITIAL.
    APPEND m_select_row TO m_index_rows.

  ENDMETHOD.                    "set_index_after_delete

  METHOD do_handle_toolbar.
    " importing e_object type ref to cl_alv_event_toolbar_set
    "           e_interactive type char01

    " Constatnts for button type
    CONSTANTS: c_button_normal           TYPE i VALUE 0,
               c_menu_and_default_button TYPE i VALUE 1,
               c_menu                    TYPE i VALUE 2,
               c_separator               TYPE i VALUE 3,
               c_radio_button            TYPE i VALUE 4,
               c_checkbox                TYPE i VALUE 5,
               c_menu_entry              TYPE i VALUE 6.

*    data ls_toolbar type stb_button.
    " Append separator to normal toolbar
*    clear ls_toolbar.
*    move c_separator to ls_toolbar-butn_type.
*    append ls_toolbar to e_object->mt_toolbar.
    " Append XXX report-button to normal toolbar
*    clear ls_toolbar.
*    move: 'xxx' to ls_toolbar-function,
*          icon_pdf to ls_toolbar-icon,
*          'xxx' to ls_toolbar-quickinfo,
*          '' to ls_toolbar-text,
*          '' to ls_toolbar-disabled.
*    append ls_toolbar to e_object->mt_toolbar.

  ENDMETHOD.                    "do_handle_toolbar

  METHOD do_handle_user_command.
    " importing e_ucomm type sy-ucomm

*    if e_ucomm eq 'xxx'.
*
*    endif.

  ENDMETHOD.                    "do_handle_user_command

  METHOD do_double_click_command.
    " importing e_row     type lvc_s_row  optional
    "           e_column  type lvc_s_col  optional
    "           es_row_no type lvc_s_roid optional

  ENDMETHOD.                    "do_double_click_command

  METHOD do_hotspot_click_command.
    " importing e_row_id     type lvc_s_row   optional
    "           e_column_id  type lvc_s_col   optional
    "           es_row_no    type lvc_s_roid  optional

*    data: l_tabix type i,
*          l_field type string.
*
*    move: e_row_id-index        to l_tabix,
*          e_column_id-fieldname to l_field.

  ENDMETHOD.                    "do_hotspot_click_command

ENDCLASS.                    "lcl_gui_grid_screen IMPLEMENTATION
Дополнительно, в программе реализован паттерны Singleton (класс приложения), Decorator (для подэкранов), Adapter и др.

Комментарии