mirror of
https://github.com/abapGit/abapGit.git
synced 2025-04-30 11:46:38 +08:00
581 lines
16 KiB
ABAP
581 lines
16 KiB
ABAP
CLASS zcl_abapgit_gui DEFINITION
|
|
PUBLIC
|
|
CREATE PUBLIC .
|
|
|
|
PUBLIC SECTION.
|
|
|
|
INTERFACES zif_abapgit_gui_services .
|
|
|
|
CONSTANTS:
|
|
BEGIN OF c_event_state,
|
|
not_handled TYPE i VALUE 0,
|
|
re_render TYPE i VALUE 1,
|
|
new_page TYPE i VALUE 2,
|
|
go_back TYPE i VALUE 3,
|
|
no_more_act TYPE i VALUE 4,
|
|
new_page_w_bookmark TYPE i VALUE 5,
|
|
go_back_to_bookmark TYPE i VALUE 6,
|
|
new_page_replacing TYPE i VALUE 7,
|
|
END OF c_event_state .
|
|
METHODS go_home
|
|
IMPORTING
|
|
iv_action TYPE string
|
|
RAISING
|
|
zcx_abapgit_exception .
|
|
METHODS back
|
|
IMPORTING
|
|
!iv_to_bookmark TYPE abap_bool DEFAULT abap_false
|
|
!iv_graceful TYPE abap_bool DEFAULT abap_false
|
|
RETURNING
|
|
VALUE(rv_exit) TYPE abap_bool
|
|
RAISING
|
|
zcx_abapgit_exception .
|
|
METHODS back_graceful
|
|
RETURNING
|
|
VALUE(rv_handled) TYPE abap_bool
|
|
RAISING
|
|
zcx_abapgit_exception .
|
|
METHODS on_event
|
|
FOR EVENT sapevent OF zif_abapgit_html_viewer
|
|
IMPORTING
|
|
!action
|
|
!frame
|
|
!getdata
|
|
!postdata
|
|
!query_table .
|
|
METHODS constructor
|
|
IMPORTING
|
|
!io_component TYPE REF TO object OPTIONAL
|
|
!ii_asset_man TYPE REF TO zif_abapgit_gui_asset_manager OPTIONAL
|
|
!ii_hotkey_ctl TYPE REF TO zif_abapgit_gui_hotkey_ctl OPTIONAL
|
|
!ii_html_processor TYPE REF TO zif_abapgit_gui_html_processor OPTIONAL
|
|
!iv_rollback_on_error TYPE abap_bool DEFAULT abap_true
|
|
RAISING
|
|
zcx_abapgit_exception .
|
|
METHODS free .
|
|
METHODS set_focus
|
|
RAISING
|
|
zcx_abapgit_exception .
|
|
PROTECTED SECTION.
|
|
PRIVATE SECTION.
|
|
|
|
TYPES:
|
|
BEGIN OF ty_page_stack,
|
|
page TYPE REF TO zif_abapgit_gui_renderable,
|
|
bookmark TYPE abap_bool,
|
|
END OF ty_page_stack .
|
|
|
|
DATA mv_rollback_on_error TYPE abap_bool .
|
|
DATA mi_cur_page TYPE REF TO zif_abapgit_gui_renderable .
|
|
DATA mt_stack TYPE STANDARD TABLE OF ty_page_stack .
|
|
DATA mt_event_handlers TYPE STANDARD TABLE OF REF TO zif_abapgit_gui_event_handler .
|
|
DATA mi_router TYPE REF TO zif_abapgit_gui_event_handler .
|
|
DATA mi_asset_man TYPE REF TO zif_abapgit_gui_asset_manager .
|
|
DATA mi_hotkey_ctl TYPE REF TO zif_abapgit_gui_hotkey_ctl .
|
|
DATA mi_html_processor TYPE REF TO zif_abapgit_gui_html_processor .
|
|
DATA mi_html_viewer TYPE REF TO zif_abapgit_html_viewer .
|
|
DATA mo_html_parts TYPE REF TO zcl_abapgit_html_parts .
|
|
DATA mi_common_log TYPE REF TO zif_abapgit_log .
|
|
|
|
|
|
METHODS cache_html
|
|
IMPORTING
|
|
!iv_text TYPE string
|
|
RETURNING
|
|
VALUE(rv_url) TYPE string
|
|
RAISING
|
|
zcx_abapgit_exception .
|
|
METHODS startup
|
|
RAISING
|
|
zcx_abapgit_exception .
|
|
METHODS render
|
|
RAISING
|
|
zcx_abapgit_exception .
|
|
METHODS call_page
|
|
IMPORTING
|
|
!ii_page TYPE REF TO zif_abapgit_gui_renderable
|
|
!iv_with_bookmark TYPE abap_bool DEFAULT abap_false
|
|
!iv_replacing TYPE abap_bool DEFAULT abap_false
|
|
RAISING
|
|
zcx_abapgit_exception .
|
|
METHODS handle_action
|
|
IMPORTING
|
|
!iv_action TYPE c
|
|
!iv_getdata TYPE c OPTIONAL
|
|
!it_postdata TYPE zif_abapgit_html_viewer=>ty_post_data OPTIONAL .
|
|
METHODS handle_error
|
|
IMPORTING
|
|
!ix_exception TYPE REF TO zcx_abapgit_exception .
|
|
METHODS is_page_modal
|
|
IMPORTING
|
|
!ii_page TYPE REF TO zif_abapgit_gui_renderable
|
|
RETURNING
|
|
VALUE(rv_yes) TYPE abap_bool .
|
|
ENDCLASS.
|
|
|
|
|
|
|
|
CLASS zcl_abapgit_gui IMPLEMENTATION.
|
|
|
|
|
|
METHOD back.
|
|
|
|
DATA lv_index TYPE i.
|
|
DATA ls_stack LIKE LINE OF mt_stack.
|
|
|
|
" If viewer is showing Internet page, then use browser navigation
|
|
IF mi_html_viewer->get_url( ) CP 'http*'.
|
|
mi_html_viewer->back( ).
|
|
RETURN.
|
|
ENDIF.
|
|
|
|
lv_index = lines( mt_stack ).
|
|
|
|
IF lv_index = 0.
|
|
rv_exit = abap_true.
|
|
RETURN.
|
|
ENDIF.
|
|
|
|
IF iv_graceful = abap_true AND back_graceful( ) = abap_true.
|
|
RETURN.
|
|
ENDIF.
|
|
|
|
DO lv_index TIMES.
|
|
READ TABLE mt_stack INDEX lv_index INTO ls_stack.
|
|
ASSERT sy-subrc = 0.
|
|
|
|
DELETE mt_stack INDEX lv_index.
|
|
ASSERT sy-subrc = 0.
|
|
|
|
lv_index = lv_index - 1.
|
|
|
|
IF iv_to_bookmark = abap_false OR ls_stack-bookmark = abap_true.
|
|
EXIT.
|
|
ENDIF.
|
|
ENDDO.
|
|
|
|
mi_cur_page = ls_stack-page. " last page always stays
|
|
render( ).
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD back_graceful.
|
|
|
|
DATA li_handler TYPE REF TO zif_abapgit_gui_event_handler.
|
|
DATA ls_handled TYPE zif_abapgit_gui_event_handler=>ty_handling_result.
|
|
|
|
" This code can be potentially improved
|
|
" Why send go_back to the topmost handler only ? It makes sense to notify the whole stack
|
|
" But than how to handle re-render ? render if at least one handler asks for it ?
|
|
" Probably that's the way but needs a relevant example. Postponed arch decision.
|
|
READ TABLE mt_event_handlers INTO li_handler INDEX 1.
|
|
IF sy-subrc = 0.
|
|
ls_handled = li_handler->on_event( zcl_abapgit_gui_event=>new(
|
|
iv_action = zif_abapgit_definitions=>c_action-go_back
|
|
ii_gui_services = me ) ).
|
|
IF ls_handled-state = c_event_state-re_render. " soft exit, probably popup
|
|
render( ).
|
|
rv_handled = abap_true.
|
|
ELSEIF ls_handled-state = c_event_state-no_more_act. " soft exit, probably GUI popup
|
|
rv_handled = abap_true.
|
|
ENDIF.
|
|
ENDIF.
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD cache_html.
|
|
|
|
rv_url = zif_abapgit_gui_services~cache_asset(
|
|
iv_text = iv_text
|
|
iv_type = 'text'
|
|
iv_subtype = 'html' ).
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD call_page.
|
|
|
|
DATA: ls_stack TYPE ty_page_stack.
|
|
|
|
IF iv_replacing = abap_false AND NOT mi_cur_page IS INITIAL.
|
|
ls_stack-page = mi_cur_page.
|
|
ls_stack-bookmark = iv_with_bookmark.
|
|
APPEND ls_stack TO mt_stack.
|
|
ENDIF.
|
|
|
|
mi_cur_page = ii_page.
|
|
render( ).
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD constructor.
|
|
|
|
IF io_component IS BOUND.
|
|
IF zcl_abapgit_gui_utils=>is_renderable( io_component ) = abap_true.
|
|
mi_cur_page ?= io_component. " direct page
|
|
ELSE.
|
|
IF zcl_abapgit_gui_utils=>is_event_handler( io_component ) = abap_false.
|
|
zcx_abapgit_exception=>raise( 'Component must be renderable or be an event handler' ).
|
|
ENDIF.
|
|
mi_router ?= io_component.
|
|
ENDIF.
|
|
ENDIF.
|
|
|
|
CREATE OBJECT mo_html_parts.
|
|
|
|
mv_rollback_on_error = iv_rollback_on_error.
|
|
mi_asset_man = ii_asset_man.
|
|
mi_hotkey_ctl = ii_hotkey_ctl.
|
|
mi_html_processor = ii_html_processor. " Maybe improve to middlewares stack ??
|
|
startup( ).
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD free.
|
|
|
|
SET HANDLER on_event FOR mi_html_viewer ACTIVATION space.
|
|
mi_html_viewer->close_document( ).
|
|
mi_html_viewer->free( ).
|
|
FREE mi_html_viewer.
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD go_home.
|
|
|
|
DATA ls_stack LIKE LINE OF mt_stack.
|
|
|
|
IF mi_router IS BOUND.
|
|
CLEAR: mt_stack, mt_event_handlers.
|
|
APPEND mi_router TO mt_event_handlers.
|
|
|
|
on_event( action = |{ iv_action }| ).
|
|
ELSE.
|
|
IF lines( mt_stack ) > 0.
|
|
READ TABLE mt_stack INTO ls_stack INDEX 1.
|
|
mi_cur_page = ls_stack-page.
|
|
ENDIF.
|
|
render( ).
|
|
ENDIF.
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD handle_action.
|
|
|
|
DATA:
|
|
lx_exception TYPE REF TO zcx_abapgit_exception,
|
|
li_handler TYPE REF TO zif_abapgit_gui_event_handler,
|
|
li_event TYPE REF TO zif_abapgit_gui_event,
|
|
ls_handled TYPE zif_abapgit_gui_event_handler=>ty_handling_result.
|
|
|
|
CREATE OBJECT li_event TYPE zcl_abapgit_gui_event
|
|
EXPORTING
|
|
ii_gui_services = me
|
|
iv_action = iv_action
|
|
iv_getdata = iv_getdata
|
|
it_postdata = it_postdata.
|
|
|
|
TRY.
|
|
ls_handled = zcl_abapgit_exit=>get_instance( )->on_event( li_event ).
|
|
|
|
IF ls_handled-state = c_event_state-not_handled.
|
|
LOOP AT mt_event_handlers INTO li_handler.
|
|
ls_handled = li_handler->on_event( li_event ).
|
|
IF ls_handled-state IS NOT INITIAL AND ls_handled-state <> c_event_state-not_handled. " is handled
|
|
EXIT.
|
|
ENDIF.
|
|
ENDLOOP.
|
|
ENDIF.
|
|
|
|
IF is_page_modal( mi_cur_page ) = abap_true AND NOT (
|
|
ls_handled-state = c_event_state-re_render OR
|
|
ls_handled-state = c_event_state-go_back OR
|
|
ls_handled-state = c_event_state-no_more_act ).
|
|
" Restrict new page switching from modals
|
|
ls_handled-state = c_event_state-no_more_act.
|
|
ENDIF.
|
|
|
|
CASE ls_handled-state.
|
|
WHEN c_event_state-re_render.
|
|
render( ).
|
|
WHEN c_event_state-new_page.
|
|
call_page( ls_handled-page ).
|
|
WHEN c_event_state-new_page_w_bookmark.
|
|
call_page(
|
|
ii_page = ls_handled-page
|
|
iv_with_bookmark = abap_true ).
|
|
WHEN c_event_state-new_page_replacing.
|
|
call_page(
|
|
ii_page = ls_handled-page
|
|
iv_replacing = abap_true ).
|
|
WHEN c_event_state-go_back.
|
|
back( ).
|
|
WHEN c_event_state-go_back_to_bookmark.
|
|
back( iv_to_bookmark = abap_true ).
|
|
WHEN c_event_state-no_more_act.
|
|
" Do nothing, handling completed
|
|
WHEN OTHERS.
|
|
zcx_abapgit_exception=>raise( |Unknown action: { iv_action }| ).
|
|
ENDCASE.
|
|
|
|
CATCH zcx_abapgit_cancel ##NO_HANDLER.
|
|
" Do nothing = c_event_state-no_more_act
|
|
CATCH zcx_abapgit_exception INTO lx_exception.
|
|
handle_error( lx_exception ).
|
|
ENDTRY.
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD handle_error.
|
|
|
|
DATA: li_gui_error_handler TYPE REF TO zif_abapgit_gui_error_handler,
|
|
lx_exception TYPE REF TO cx_root.
|
|
|
|
IF mv_rollback_on_error = abap_true.
|
|
ROLLBACK WORK.
|
|
ENDIF.
|
|
|
|
TRY.
|
|
li_gui_error_handler ?= mi_cur_page.
|
|
|
|
IF li_gui_error_handler IS BOUND AND li_gui_error_handler->handle_error( ix_exception ) = abap_true.
|
|
" We rerender the current page to display the error box
|
|
render( ).
|
|
ELSEIF ix_exception->mi_log IS BOUND.
|
|
mi_common_log = ix_exception->mi_log.
|
|
IF mi_common_log->get_log_level( ) >= zif_abapgit_log=>c_log_level-warning.
|
|
zcl_abapgit_log_viewer=>show_log( mi_common_log ).
|
|
ENDIF.
|
|
ELSE.
|
|
MESSAGE ix_exception TYPE 'S' DISPLAY LIKE 'E'.
|
|
ENDIF.
|
|
|
|
CATCH zcx_abapgit_exception cx_sy_move_cast_error INTO lx_exception.
|
|
" In case of fire we just fallback to plain old message
|
|
MESSAGE lx_exception TYPE 'S' DISPLAY LIKE 'E'.
|
|
ENDTRY.
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD is_page_modal.
|
|
|
|
DATA li_modal TYPE REF TO zif_abapgit_gui_modal.
|
|
|
|
TRY.
|
|
IF ii_page IS BOUND.
|
|
li_modal ?= ii_page.
|
|
rv_yes = li_modal->is_modal( ).
|
|
ENDIF.
|
|
CATCH cx_sy_move_cast_error ##NO_HANDLER.
|
|
ENDTRY.
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD on_event.
|
|
|
|
handle_action(
|
|
iv_action = action
|
|
iv_getdata = getdata
|
|
it_postdata = postdata ).
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD render.
|
|
|
|
DATA: lv_url TYPE string,
|
|
lv_html TYPE string,
|
|
li_html TYPE REF TO zif_abapgit_html.
|
|
|
|
IF mi_cur_page IS NOT BOUND.
|
|
zcx_abapgit_exception=>raise( 'GUI error: no current page' ).
|
|
ENDIF.
|
|
|
|
CLEAR mt_event_handlers.
|
|
mo_html_parts->clear( ).
|
|
|
|
IF mi_router IS BOUND AND is_page_modal( mi_cur_page ) = abap_false.
|
|
" No global commands in modals
|
|
APPEND mi_router TO mt_event_handlers.
|
|
ENDIF.
|
|
|
|
IF mi_hotkey_ctl IS BOUND.
|
|
mi_hotkey_ctl->reset( ).
|
|
ENDIF.
|
|
|
|
li_html = mi_cur_page->render( ).
|
|
lv_html = li_html->render( iv_no_indent_jscss = abap_true ).
|
|
|
|
IF mi_html_processor IS BOUND.
|
|
lv_html = mi_html_processor->process(
|
|
iv_html = lv_html
|
|
ii_gui_services = me ).
|
|
ENDIF.
|
|
|
|
lv_url = cache_html( lv_html ).
|
|
mi_html_viewer->show_url( lv_url ).
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD set_focus.
|
|
mi_html_viewer->set_focus( ).
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD startup.
|
|
|
|
DATA: lt_events TYPE cntl_simple_events,
|
|
ls_event LIKE LINE OF lt_events,
|
|
lt_assets TYPE zif_abapgit_gui_asset_manager=>ty_web_assets.
|
|
|
|
FIELD-SYMBOLS <ls_asset> LIKE LINE OF lt_assets.
|
|
|
|
|
|
mi_html_viewer = zcl_abapgit_ui_core_factory=>get_html_viewer( ).
|
|
|
|
IF mi_asset_man IS BOUND.
|
|
lt_assets = mi_asset_man->get_all_assets( ).
|
|
LOOP AT lt_assets ASSIGNING <ls_asset> WHERE is_cacheable = abap_true.
|
|
zif_abapgit_gui_services~cache_asset(
|
|
iv_xdata = <ls_asset>-content
|
|
iv_url = <ls_asset>-url
|
|
iv_type = <ls_asset>-type
|
|
iv_subtype = <ls_asset>-subtype ).
|
|
ENDLOOP.
|
|
ENDIF.
|
|
|
|
ls_event-eventid = mi_html_viewer->c_id_sapevent.
|
|
ls_event-appl_event = abap_true.
|
|
APPEND ls_event TO lt_events.
|
|
|
|
mi_html_viewer->set_registered_events( lt_events ).
|
|
SET HANDLER on_event FOR mi_html_viewer.
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD zif_abapgit_gui_services~cache_asset.
|
|
|
|
TYPES ty_hex TYPE x LENGTH 200.
|
|
TYPES ty_char TYPE c LENGTH 200.
|
|
|
|
DATA: lt_xdata TYPE STANDARD TABLE OF ty_hex WITH DEFAULT KEY,
|
|
lv_size TYPE i,
|
|
lt_html TYPE STANDARD TABLE OF ty_char WITH DEFAULT KEY.
|
|
|
|
ASSERT iv_text IS SUPPLIED OR iv_xdata IS SUPPLIED.
|
|
|
|
IF iv_text IS SUPPLIED. " String input
|
|
zcl_abapgit_convert=>string_to_tab(
|
|
EXPORTING
|
|
iv_str = iv_text
|
|
IMPORTING
|
|
ev_size = lv_size
|
|
et_tab = lt_html ).
|
|
|
|
mi_html_viewer->load_data(
|
|
EXPORTING
|
|
iv_type = iv_type
|
|
iv_subtype = iv_subtype
|
|
iv_size = lv_size
|
|
iv_url = iv_url
|
|
IMPORTING
|
|
ev_assigned_url = rv_url
|
|
CHANGING
|
|
ct_data_table = lt_html ).
|
|
ELSE. " Raw input
|
|
zcl_abapgit_convert=>xstring_to_bintab(
|
|
EXPORTING
|
|
iv_xstr = iv_xdata
|
|
IMPORTING
|
|
ev_size = lv_size
|
|
et_bintab = lt_xdata ).
|
|
|
|
mi_html_viewer->load_data(
|
|
EXPORTING
|
|
iv_type = iv_type
|
|
iv_subtype = iv_subtype
|
|
iv_size = lv_size
|
|
iv_url = iv_url
|
|
IMPORTING
|
|
ev_assigned_url = rv_url
|
|
CHANGING
|
|
ct_data_table = lt_xdata ).
|
|
ENDIF.
|
|
|
|
ASSERT sy-subrc = 0. " Image data error
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD zif_abapgit_gui_services~get_current_page_name.
|
|
|
|
DATA li_page_hoc TYPE REF TO zcl_abapgit_gui_page_hoc.
|
|
|
|
IF mi_cur_page IS BOUND.
|
|
rv_page_name = cl_abap_classdescr=>describe_by_object_ref( mi_cur_page )->get_relative_name( ).
|
|
|
|
" For HOC components return name of child component instead
|
|
IF rv_page_name = 'ZCL_ABAPGIT_GUI_PAGE_HOC'.
|
|
li_page_hoc ?= mi_cur_page.
|
|
IF li_page_hoc->get_child( ) IS BOUND.
|
|
rv_page_name = cl_abap_classdescr=>describe_by_object_ref(
|
|
li_page_hoc->get_child( ) )->get_relative_name( ).
|
|
ENDIF.
|
|
ENDIF.
|
|
ENDIF." ELSE - return is empty => initial page
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD zif_abapgit_gui_services~get_hotkeys_ctl.
|
|
ri_hotkey_ctl = mi_hotkey_ctl.
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD zif_abapgit_gui_services~get_html_parts.
|
|
ro_parts = mo_html_parts.
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD zif_abapgit_gui_services~get_log.
|
|
|
|
IF iv_create_new = abap_true OR mi_common_log IS NOT BOUND.
|
|
CREATE OBJECT mi_common_log TYPE zcl_abapgit_log.
|
|
ENDIF.
|
|
|
|
ri_log = mi_common_log.
|
|
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD zif_abapgit_gui_services~register_event_handler.
|
|
ASSERT ii_event_handler IS BOUND.
|
|
INSERT ii_event_handler INTO mt_event_handlers INDEX 1.
|
|
ENDMETHOD.
|
|
|
|
|
|
METHOD zif_abapgit_gui_services~register_page_asset.
|
|
|
|
" Maybe forbid registering cacheable existing assets, maybe this is the right place (see also asset_man comments)
|
|
|
|
mi_asset_man->register_asset(
|
|
iv_url = iv_url
|
|
iv_type = iv_type
|
|
iv_mime_name = iv_mime_name
|
|
iv_inline = iv_inline
|
|
" This registering will happen after initialization so all cacheable already cached
|
|
iv_cacheable = abap_false ).
|
|
|
|
ENDMETHOD.
|
|
ENDCLASS.
|