Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
nomssi
Active Contributor

Introduction


Evidence from ABAP blogs suggests developers communicate to their audience using

  • A lot of (technical) text,

  • (ABAP) code blocks,

  • Some (annotated) screenshots,

  • Few pictures,

  • Little or no diagrams.


For most of us, a diagram is easier to consume than text. Each diagram type communicates intent in a special way. It helps to reason about software and eases knowledge transfer. So many disparate notations were created that they had to be standardized.

Nowadays, the Unified Modeling Language (UML) is an established notation to visualize designs using following diagram types:

Hierarchy of UML 2.2 Diagrams, shown as a class diagram

UML Essentials


To decide which diagram type communicates our intent best, we must understand its essential features. I will single out

  • Requirement specifications: we might want to visualize requirements in a use case diagram  (also check: activity diagrams, state diagrams)

  • Modularization elements: we want to provide a bird's-eye view of the code structure using class diagrams  (object diagrams, composite structure diagram)

  • The dynamic behavior of code: we want to emphasize interfaces in a sequence diagram. (or timing diagram)


and refer to some tutorials, e.g.

How to Create Diagrams


Create a rough sketch on paper by hand, capture the picture with a phone/camera and upload it.



OK, I have to work on my skills and do image pre-processing, but this is probably as easy as creating an annotated screenshot.

Without appropriate tools, creating diagrams (e.g. like this one)



would take too much time, we will see copy/pasted source code in the documentation. Many visualization tools are available, some free (search the web for free UML tools), others with a price tag and easy to use templates. I will propose to select one and get used to it, so the effort needed to create those diagrams is reduced.

Try PlantUML


Let me introduce you to the open source PlantUML tool that creates UML diagrams from plain text. It uses the graph visualization software Graphviz to lay out diagrams of remarkable quality.

PlantUML (site http://plantuml.com/) is a mature project integrated with many content management systems, text editors and other tools. At least 2 existing blogs reference PlantUML on SCN:

The concept of working with plain text should resonate with programmers. The API can be called from many programming languages. I present an ABAP interface to the PlantUML web service in the appendix.

With the hope that we will see more diagrams, as the costs/effort to create them are reduced.

State Diagram


Real programmers do not read documentation: go to the PlantUML online server, enter:
@startuml
[*] --> ContractHeader
ContractHeader : Screen 201
ContractHeader --> Partners
Partners : Screens 102, 101, 201
Partners --> ProcessItems
state ProcessItems {
ItemsOverview --> ItemsDetail
ItemsOverview : Screens 220, 221
ItemsDetail : Screens 211
ItemsDetail -> ItemsAddData
ItemsAddData : Screens 212
}
ProcessItems --> [*]
@enduml

and get this!


Activity Diagrams


This diagram type is well suited for the description of processes. ABAP code using FORM as modularization unit is easier to reason about if the code reflects the hierarchy of the abstraction levels (top down decomposition).
@startuml
start
:Init Transaction;
:Query Documents
- Fecth Header
- Authority Check
- Fetch all items
- Additional Data;
if (Entry found?) then (View)
:ALV Display;
else (Error)
:Message;
endif
stop
@enduml


Class Diagrams


describe the static structure (topology) of the code. We want classes with single responsibility, where the abstractions are visible in the code structure.
@startuml
LCL_FILTER <|-- LCL_FILTER_NULL
LCL_FILTER <|-- LCL_FILTER_CUSTOM

LCL_FILTER : accepts( )
LCL_FILTER_NULL : accepts( )
LCL_FILTER_CUSTOM : accepts( )
@enduml



You can already generate UML class diagrams using report UML_CLASS_DIAGRAM if you have installed the correct Java OCX plugin on your machine. Find a custom version using PlantUML in the appendix.

Sequence Diagrams


This diagram type visualizes coupling between objects. Code is easier to change when objects working have minimal knowledge about each other.
@startuml
hide footbox
actor User
User -> LCL_PRICE : Process( )
LCL_PRICE -> LCL_INFREC : Transfer( )
LCL_INFREC -> LCL_BDC : PRICE_UPDATE( )

box "Internal Service" #LightBlue
participant LCL_INFREC
participant LCL_BDC
end box
@enduml



You can generate sequence diagrams using transaction SAT.

Summary


Diagrams are more expressive than code but tools are needed. Try PlantUML at http://plantuml.com/.



Appendix



  • This program generates UML class diagrams automatically from existing ABAP code.

  • The diagrams are generated and displayed from the SAP GUI without any further settings.

  • Local class LCL_PLANT_UML implements access to the PlantUML web service.



*&---------------------------------------------------------------------*
"! UML Class XMI exporter (inspired by program UML_CLASS_DIAGRAM)
"! Installation of JNET is not required.
REPORT zz_uml_class_export.

*NAME TEXT
*SO_DEVC Package
*SO_ROOT Object Name
*X_AGGR Aggregations (<>--)
*X_ASOS Associations (-->)
*X_ATTR List Attributes
*X_CONS Display Constants
*X_EXCEP Exceptions (<<throws>>)
*X_FRND Friends
*X_FUGR Analyze Function Groups
*X_LOCL Analyze Local Objects
*X_METH List Methods
*X_PACKS Package Member (~)
*X_PRIV Private Member (-)
*X_PROG Analyze Program
*X_PROT Protected Member (#)
*X_STRUCT Structures (<<data Type>>)
*X_USES Dependency (<<uses>>)

*SYMBOL TEXT
*007 Primary Selection Set
*008 Statements UML Scanner
*009 UML Representation Options
*SC1 Selection of Dev. Objects to Be Evaluated
*SC2 Options for Display of UML Class Diagrams
*SC7 Work Instructions for UML Scanner
*P01 PlantUML

TABLES sscrfields. " Selection Screen Fields

SELECTION-SCREEN FUNCTION KEY 1. "#EC CI_USE_WANTED
SELECTION-SCREEN FUNCTION KEY 2. "#EC CI_USE_WANTED

DATA gs_tadir TYPE tadir.
" ----------------------------------------------------------------------------------------------------------------------------------- *
" selection screen definition
SELECTION-SCREEN: BEGIN OF TABBED BLOCK mytab FOR 18 LINES,
TAB (40) button1 USER-COMMAND push1 DEFAULT SCREEN 510,
TAB (40) button2 USER-COMMAND push2 DEFAULT SCREEN 520,
TAB (40) button3 USER-COMMAND push3 DEFAULT SCREEN 530,
END OF BLOCK mytab.

" primary selection criteria
SELECTION-SCREEN BEGIN OF SCREEN 510 AS SUBSCREEN.
SELECTION-SCREEN BEGIN OF BLOCK s1 WITH FRAME TITLE text-sc1.
SELECT-OPTIONS: so_root FOR gs_tadir-obj_name, " root objects
so_devc FOR gs_tadir-devclass. " root objects dev-class
SELECTION-SCREEN END OF BLOCK s1.
SELECTION-SCREEN END OF SCREEN 510.

" UML scanner parameters
SELECTION-SCREEN BEGIN OF SCREEN 520 AS SUBSCREEN.
SELECTION-SCREEN BEGIN OF BLOCK b0 WITH FRAME TITLE text-sc7.
PARAMETERS: x_locl TYPE flag AS CHECKBOX DEFAULT 'X',
x_prog TYPE flag AS CHECKBOX DEFAULT 'X',
x_fugr TYPE flag AS CHECKBOX DEFAULT 'X',
x_struct TYPE flag AS CHECKBOX DEFAULT ' '.
SELECTION-SCREEN END OF BLOCK b0.
SELECTION-SCREEN END OF SCREEN 520.

" diagram option parameters
SELECTION-SCREEN BEGIN OF SCREEN 530 AS SUBSCREEN.
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-sc2.
PARAMETERS: x_priv TYPE flag AS CHECKBOX DEFAULT 'X',
x_prot TYPE flag AS CHECKBOX DEFAULT 'X',
x_packs TYPE flag AS CHECKBOX DEFAULT 'X',
x_attr TYPE flag AS CHECKBOX DEFAULT 'X',
x_cons TYPE flag AS CHECKBOX DEFAULT 'X',
x_meth TYPE flag AS CHECKBOX DEFAULT 'X',
x_uses TYPE flag AS CHECKBOX DEFAULT ' ',
x_frnd TYPE flag AS CHECKBOX DEFAULT 'X',
x_excep TYPE flag AS CHECKBOX DEFAULT ' ',
x_asos TYPE flag AS CHECKBOX DEFAULT ' ',
x_aggr TYPE flag AS CHECKBOX DEFAULT ' '.
SELECTION-SCREEN END OF BLOCK b1.
SELECTION-SCREEN END OF SCREEN 530.

" ----------------------------------------------------------------------------------------------------------------------------------- *
" types/classes/interfaces

TYPES: BEGIN OF ts_uml_config,
show_aggregations TYPE flag, " show aggregations
show_associations TYPE flag, " show associations
show_uses TYPE flag, " <<call>> show dependencies
show_friends TYPE flag, " show friends
show_throws TYPE flag, " show used exceptions
END OF ts_uml_config.

TYPES: BEGIN OF ts_scan_config,
attributes TYPE flag,
methods TYPE flag,
constants TYPE flag,
private_member TYPE flag,
protected_member TYPE flag,
packaged_member TYPE flag,

scan_local_types TYPE flag,
scan_programs TYPE flag,
scan_function_groups TYPE flag,
add_structures TYPE flag,
scan_used_types TYPE flag,
END OF ts_scan_config.


TYPES tv_scale TYPE perct.
CONSTANTS c_default_scale TYPE tv_scale VALUE '0.6'.
TYPES: BEGIN OF ts_diagram_config,
local_path TYPE string,
java_jar TYPE string,
java_appl TYPE string,
server_url TYPE string,
output_mode TYPE char01,
skip_dialog TYPE flag,
scale TYPE tv_scale,
handwritten TYPE flag,
shadowing TYPE flag,
display_source TYPE flag,
END OF ts_diagram_config.

*----------------------------------------------------------------------*
* INTERFACE lif_unit_test
*----------------------------------------------------------------------*
INTERFACE lif_unit_test.
ENDINTERFACE. "lif_unit_test

"! Parameter Interface
*----------------------------------------------------------------------*
* INTERFACE lif_parameter
*----------------------------------------------------------------------*
INTERFACE lif_parameter.
METHODS get_display_config RETURNING VALUE(rs_cfg) TYPE ts_uml_config.
METHODS get_scan_config RETURNING VALUE(rs_scan) TYPE ts_scan_config.
METHODS get_scan_ranges CHANGING ct_so_packages TYPE cl_uml_class_scanner=>uml_range_packages
ct_so_objects TYPE cl_uml_class_scanner=>uml_range_types.
ENDINTERFACE. "lif_parameter

"! Parameter Class
*----------------------------------------------------------------------*
* CLASS lcl_parameter DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_parameter DEFINITION.
PUBLIC SECTION.
INTERFACES lif_parameter.

"! constructor
"! @parameter iv_progname | program name
METHODS constructor IMPORTING iv_progname TYPE progname.

PRIVATE SECTION.
TYPES tt_options TYPE RANGE OF text30.
"! selection screen parameters
DATA mt_parameters TYPE SORTED TABLE OF rsparamsl_255 WITH NON-UNIQUE KEY selname.

METHODS get_boolean IMPORTING iv_parameter_name TYPE selname
RETURNING VALUE(rv_value) TYPE flag
RAISING cx_dynamic_check.

METHODS get_user_input IMPORTING iv_progname TYPE raldb_repo.

"! get select option table parameter
"! @parameter rt_so_value | selection option values
METHODS get_parameter_so_tab IMPORTING iv_parameter_name TYPE selname
RETURNING VALUE(rt_so_value) TYPE tt_options.
ENDCLASS. "lcl_parameter DEFINITION

CLASS lcl_scanner DEFINITION INHERITING FROM cl_uml_class_scanner.
PUBLIC SECTION.
METHODS constructor IMPORTING ii_parameter TYPE REF TO lif_parameter.
METHODS class_scan RETURNING VALUE(rv_objects_selected) TYPE flag.
PRIVATE SECTION.
DATA mi_parameter TYPE REF TO lif_parameter.
ENDCLASS.

* Abstract UML code generator
CLASS lcl_uml DEFINITION FRIENDS lif_unit_test.
PUBLIC SECTION.
CLASS-METHODS new IMPORTING is_cfg TYPE ts_diagram_config
RETURNING VALUE(ro_uml) TYPE REF TO lcl_uml.

METHODS add IMPORTING iv_code TYPE string.
METHODS get RETURNING VALUE(rv_diagram) TYPE string.
PROTECTED SECTION.
DATA mv_diagram TYPE string.
METHODS header IMPORTING is_cfg TYPE ts_diagram_config.
METHODS footer.
ENDCLASS. "lcl_uml DEFINITION

*----------------------------------------------------------------------*
* CLASS lcl_iterator DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_iterator DEFINITION FRIENDS lif_unit_test.
PUBLIC SECTION.
* Convert and filter the trace for further processing
TYPES ts_uml TYPE cl_uml_class_scanner=>uml_line.
TYPES tt_uml TYPE STANDARD TABLE OF ts_uml WITH KEY name.

METHODS constructor IMPORTING it_data TYPE tt_uml
iv_start TYPE sytabix DEFAULT 1
iv_stop TYPE sytabix OPTIONAL.
METHODS next RETURNING VALUE(rs_uml) TYPE ts_uml
RAISING cx_dynamic_check.
METHODS has_next RETURNING VALUE(rv_flag) TYPE xsdboolean.
METHODS skip IMPORTING iv_count TYPE i DEFAULT 1.
PROTECTED SECTION.
DATA mv_idx TYPE sytabix.
DATA mv_size TYPE sytabix.
DATA mt_data TYPE tt_uml.
ENDCLASS. "lcl_iterator DEFINITION

*----------------------------------------------------------------------*
* CLASS lcl_uml_class DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_uml_class DEFINITION FRIENDS lif_unit_test.
PUBLIC SECTION.
TYPES ts_uml TYPE lcl_iterator=>ts_uml.

METHODS constructor IMPORTING io_uml TYPE REF TO lcl_uml
is_uml_config TYPE ts_uml_config.
METHODS to_uml_text IMPORTING is_uml TYPE ts_uml.
PRIVATE SECTION.
METHODS plant_uml_class.

METHODS uml_fields.
METHODS uml_methods.
METHODS uml_events.

METHODS uml_add
IMPORTING iv_abstract TYPE xsdboolean DEFAULT abap_false
iv_visibility TYPE char01
iv_class TYPE xsdboolean
iv_name TYPE csequence.
METHODS uml_reduce IMPORTING it_data TYPE STANDARD TABLE
iv_sep TYPE char3
iv_suffix TYPE csequence OPTIONAL
iv_active TYPE xsdboolean DEFAULT abap_true.
METHODS begin_class.
METHODS end_class.

METHODS class_member.
METHODS visibility IMPORTING iv_visibility TYPE char01.

METHODS set_data IMPORTING is_uml TYPE ts_uml.

METHODS get_class RETURNING VALUE(rv_class) TYPE string.

METHODS get_name IMPORTING iv_name TYPE csequence
RETURNING VALUE(rv_name) TYPE string.
METHODS get_container RETURNING VALUE(rv_name) TYPE string.

METHODS escape IMPORTING iv_name TYPE csequence RETURNING VALUE(rv_name) TYPE string.

DATA mo_uml TYPE REF TO lcl_uml.
DATA ms_uml TYPE ts_uml.
DATA mv_name TYPE string.
DATA ms_config TYPE ts_uml_config.
ENDCLASS. "lcl_uml_class DEFINITION

CLASS lcl_file_name DEFINITION FRIENDS lif_unit_test.
PUBLIC SECTION.
CLASS-METHODS new IMPORTING iv_mode TYPE char01
RETURNING VALUE(ro_file) TYPE REF TO lcl_file_name.
METHODS constructor IMPORTING iv_mode TYPE char01.
METHODS dialog RETURNING VALUE(rv_user_action) TYPE i.
METHODS get_prefix RETURNING VALUE(rv_name) TYPE string
RAISING cx_dynamic_check.
METHODS get_fullpath RETURNING VALUE(rv_name) TYPE string.
PROTECTED SECTION.
TYPES: BEGIN OF ts_fullpath,
title TYPE string,
name TYPE string,
ext TYPE string,
path TYPE string,
filter TYPE string,
END OF ts_fullpath.
DATA ms_file TYPE ts_fullpath.
ENDCLASS.

*----------------------------------------------------------------------*
* CLASS lcl_file DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_file DEFINITION CREATE PRIVATE.
PUBLIC SECTION.
CONSTANTS:
c_mode_xmi TYPE char01 VALUE 'X',
c_mode_txt TYPE char01 VALUE space,
c_mode_png TYPE char01 VALUE 'P'.

CLASS-METHODS download
IMPORTING iv_data TYPE xstring
io_name TYPE REF TO lcl_file_name
RETURNING VALUE(rv_subrc) TYPE sysubrc.
ENDCLASS. "lcl_file DEFINITION

CLASS lcl_file_name_dummy DEFINITION INHERITING FROM lcl_file_name FRIENDS lif_unit_test.
PUBLIC SECTION.
METHODS dialog REDEFINITION.
ENDCLASS.

*----------------------------------------------------------------------*
* CLASS lcl_plant_uml DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_plant_uml DEFINITION.
PUBLIC SECTION.
CONSTANTS c_plantuml_server TYPE string
VALUE 'http://www.plantuml.com/plantuml/img/' ##NO_TEXT.

METHODS constructor IMPORTING iv_diagram TYPE string.
METHODS to_url IMPORTING iv_base_url TYPE string DEFAULT c_plantuml_server
RETURNING VALUE(rv_url) TYPE string
RAISING cx_dynamic_check.
METHODS output IMPORTING is_cfg TYPE ts_diagram_config RAISING cx_dynamic_check.
PROTECTED SECTION.
TYPES tv_base64 TYPE c LENGTH 65.
CONSTANTS:
c_standard TYPE tv_base64 VALUE 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' ##NO_TEXT,
c_plantuml TYPE tv_base64 VALUE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_0' ##NO_TEXT.
DATA mv_diagram TYPE string.

METHODS to_xstring IMPORTING iv_string TYPE string
RETURNING VALUE(rv_xstring) TYPE xstring
RAISING cx_dynamic_check.
METHODS source IMPORTING iv_display_source TYPE flag
RETURNING VALUE(rv_source) TYPE string.

METHODS png_file_name IMPORTING io_name TYPE REF TO lcl_file_name
is_cfg TYPE ts_diagram_config
RETURNING VALUE(rv_name) TYPE string.

METHODS parameter_string IMPORTING io_name TYPE REF TO lcl_file_name
is_cfg TYPE ts_diagram_config
RETURNING VALUE(rv_param) TYPE string.
METHODS show_html IMPORTING iv_html TYPE string
RAISING cx_dynamic_check.
METHODS to_png IMPORTING io_name TYPE REF TO lcl_file_name
is_cfg TYPE ts_diagram_config
RETURNING VALUE(rv_name) TYPE string.

ENDCLASS. "lcl_plant_uml DEFINITION

"! Output interface
*----------------------------------------------------------------------*
* INTERFACE lif_output DEFINITION
*----------------------------------------------------------------------*
INTERFACE lif_output.
"! export data
"! @parameter io_uml_class_scanner | UML class scanner instance
METHODS output IMPORTING ii_parameter TYPE REF TO lif_parameter
RETURNING VALUE(rv_flag) TYPE flag.
ENDINTERFACE. "lif_output DEFINITION

CLASS lcl_xmi_output DEFINITION.
PUBLIC SECTION.
INTERFACES lif_output.
PRIVATE SECTION.
CLASS-METHODS new_xmi IMPORTING io_scanner TYPE REF TO cl_uml_class_scanner
ii_parameter TYPE REF TO lif_parameter
RETURNING VALUE(ro_xmi) TYPE REF TO cl_uml_class_decor_xmi.
ENDCLASS. "lcl_xmi_output DEFINITION

CLASS lcl_plantuml_output DEFINITION.
PUBLIC SECTION.
INTERFACES lif_output.
ENDCLASS. "lcl_plantuml_output DEFINITION

CLASS lcl_null_output DEFINITION.
PUBLIC SECTION.
INTERFACES lif_output.
ENDCLASS. "lcl_xmi_output DEFINITION

*----------------------------------------------------------------------*
* CLASS lcl_class_diagram DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_class_diagram DEFINITION INHERITING FROM lcl_iterator
CREATE PROTECTED FRIENDS lif_unit_test.
PUBLIC SECTION.
CLASS-METHODS generate
IMPORTING it_uml TYPE tt_uml
is_output_config TYPE ts_diagram_config
is_uml_config TYPE ts_uml_config
RETURNING VALUE(rv_diagram) TYPE string.
PRIVATE SECTION.
METHODS to_uml_text IMPORTING is_uml_config TYPE ts_uml_config
is_output_config TYPE ts_diagram_config
RETURNING VALUE(rv_diagram) TYPE string.
ENDCLASS. "lcl_class_diagram DEFINITION

"! export - app
*----------------------------------------------------------------------*
* CLASS lcl_app DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_app DEFINITION CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS init.
CLASS-METHODS user_command IMPORTING iv_ucomm TYPE syucomm
RETURNING VALUE(rv_flag) TYPE flag.
ENDCLASS. "lcl_app DEFINITION

CLASS lcl_configuration DEFINITION CREATE PRIVATE FRIENDS lif_unit_test.
PUBLIC SECTION.
CONSTANTS:
c_mode_aut TYPE char01 VALUE 'T', " for ABAP Unit Test
c_mode_url TYPE char01 VALUE 'U',
c_mode_txt TYPE char01 VALUE space,
c_mode_xmi TYPE char01 VALUE 'X',
c_mode_exe TYPE char01 VALUE 'E'.

CLASS-METHODS:
get RETURNING VALUE(rs_cfg) TYPE ts_diagram_config,
query RETURNING VALUE(rs_cfg) TYPE ts_diagram_config,
class_constructor.
PRIVATE SECTION.
TYPES: BEGIN OF ts_param,
local_path TYPE localfile,
java_jar TYPE localfile,
java_appl TYPE localfile,
server_url TYPE localfile,
output_mode TYPE char01,
skip_dialog TYPE flag,
scale TYPE perct,
handwritten TYPE flag,
shadowing TYPE flag,
display_source TYPE flag,
END OF ts_param.
METHODS get_attributes RETURNING VALUE(rt_attr) TYPE sci_atttab.
METHODS to_radiobutton.
METHODS from_radiobutton.
CLASS-DATA gs_cfg TYPE ts_param.
DATA: mv_mode_url TYPE flag VALUE 'X',
mv_mode_exe TYPE flag,
mv_mode_txt TYPE flag.
METHODS dialog.
CLASS-METHODS get_java_path RETURNING VALUE(rv_fullpath) TYPE string.
ENDCLASS.

*--------------------------------------------------------------------------------------------------------*

CLASS lcl_parameter IMPLEMENTATION.

METHOD constructor.
get_user_input( iv_progname ).
ENDMETHOD. "constructor

METHOD get_user_input.
DATA lt_parameters TYPE TABLE OF rsparams ##needed.
DATA lt_parameters_255 TYPE TABLE OF rsparamsl_255.

CALL FUNCTION 'RS_REFRESH_FROM_SELECTOPTIONS'
EXPORTING
curr_report = iv_progname
TABLES
selection_table = lt_parameters
selection_table_255 = lt_parameters_255
EXCEPTIONS
not_found = 1
no_report = 2
OTHERS = 3.

IF sy-subrc <> 0.
CLEAR mt_parameters.
ELSE.
INSERT LINES OF lt_parameters_255 INTO TABLE mt_parameters.
ENDIF.
ENDMETHOD.

METHOD lif_parameter~get_scan_config.
rs_scan = VALUE #( attributes = get_boolean( 'X_ATTR' )
methods = get_boolean( 'X_METH' )
constants = get_boolean( 'X_CONS' )
private_member = get_boolean( 'X_PRIV' )
protected_member = get_boolean( 'X_PROT' )
packaged_member = get_boolean( 'X_PACKS' )

scan_local_types = get_boolean( 'X_LOCL' )
scan_programs = get_boolean( 'X_PROG' )
scan_function_groups = get_boolean( 'X_FUGR' )
add_structures = get_boolean( 'X_STRUCT' )
scan_used_types = get_boolean( 'X_USES' ) ).
ENDMETHOD.

METHOD lif_parameter~get_display_config.
rs_cfg = VALUE #( show_aggregations = get_boolean( 'X_AGGR' )
show_associations = get_boolean( 'X_ASOS' )
show_uses = get_boolean( 'X_USES' ) " Display Dependencies
show_friends = get_boolean( 'X_FRND' ) " Display Friend Relationship
show_throws = get_boolean( 'X_EXCEP' ) ).
ENDMETHOD. "lif_parameter~get_config

METHOD get_boolean.
rv_value = mt_parameters[ selname = iv_parameter_name ]-low.
ENDMETHOD. "get_boolean

METHOD get_parameter_so_tab.
rt_so_value = VALUE #( FOR p IN mt_parameters
WHERE ( selname EQ iv_parameter_name AND NOT ( low IS INITIAL AND high IS INITIAL ) )
( CORRESPONDING #( p ) ) ).
ENDMETHOD. "get_parameter_so_tab

METHOD lif_parameter~get_scan_ranges.

ct_so_objects = get_parameter_so_tab( 'SO_ROOT' ). " others
ct_so_packages = get_parameter_so_tab( 'SO_DEVC' ). " packages

CHECK ct_so_packages IS INITIAL
AND ct_so_objects IS NOT INITIAL.

SELECT DISTINCT devclass as low, 'I' as sign, 'EQ' as option FROM tadir
APPENDING CORRESPONDING FIELDS OF TABLE @ct_so_packages
WHERE obj_name IN @ct_so_objects.
CHECK sy-subrc NE 0.

CLEAR ct_so_objects.
ENDMETHOD.

ENDCLASS. "lcl_parameter IMPLEMENTATION

CLASS lcl_scanner IMPLEMENTATION.

METHOD constructor.
super->constructor( ).
mi_parameter = ii_parameter.
DATA(ls_scan) = mi_parameter->get_scan_config( ).
set_scanner_configuration( scan_local_types = ls_scan-scan_local_types
scan_programs = ls_scan-scan_programs
scan_function_groups = ls_scan-scan_function_groups
add_structures = ls_scan-add_structures
scan_used_types = ls_scan-scan_used_types ).
ENDMETHOD.

METHOD class_scan.
DATA lt_packages TYPE uml_range_packages.
DATA lt_objects TYPE uml_range_types.

rv_objects_selected = abap_false.
cl_uml_cache=>get_singleton( )->clear_type_cache( ).

mi_parameter->get_scan_ranges( CHANGING ct_so_packages = lt_packages
ct_so_objects = lt_objects ).
CHECK NOT ( lt_packages IS INITIAL AND lt_objects IS INITIAL ).
rv_objects_selected = abap_true.

execute( scan_packages = lt_packages
scan_types = lt_objects ).
ENDMETHOD. "lif_parameter~uml_class_scan

ENDCLASS.

*----------------------------------------------------------------------*
* CLASS lcl_file IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_file IMPLEMENTATION.

METHOD download.
rv_subrc = 1.
CHECK io_name->dialog( ) NE cl_gui_frontend_services=>action_cancel.

rv_subrc = cl_uml_utilities=>save_xml_local( xml = iv_data
filename = io_name->get_fullpath( ) ).
ENDMETHOD.

ENDCLASS. "lcl_file IMPLEMENTATION

CLASS lcl_file_name IMPLEMENTATION.

METHOD new.
CASE iv_mode.
WHEN lcl_configuration=>c_mode_aut.
ro_file = NEW lcl_file_name_dummy( iv_mode ).
WHEN OTHERS.
ro_file = NEW lcl_file_name( iv_mode ).
ENDCASE.
ENDMETHOD.

METHOD constructor.
CASE iv_mode.
WHEN lcl_configuration=>c_mode_txt.
ms_file = VALUE #( title = |Save UML text source|
ext = |.txt| ).
WHEN lcl_configuration=>c_mode_xmi.
ms_file = VALUE #( title = |Export XMI file|
ext = |.xmi|
filter = |(*.xmi)\|*.xmi| ).
WHEN OTHERS.
ms_file = VALUE #( title = |Save As...|
ext = |.txt| ).
ENDCASE.
ENDMETHOD.

METHOD get_prefix.
rv_name = shift_right( val = ms_file-name
places = strlen( ms_file-ext ) ).
ENDMETHOD.

METHOD get_fullpath.
rv_name = ms_file-path.
ENDMETHOD.

METHOD dialog.
DATA lv_path TYPE string ##needed.

CLEAR rv_user_action.

cl_gui_frontend_services=>file_save_dialog(
EXPORTING
window_title = ms_file-title " Window Title
default_extension = ms_file-ext " Default Extension
file_filter = ms_file-filter
CHANGING
filename = ms_file-name " File Name to Save
path = lv_path " Path to File
fullpath = ms_file-path " Path + File Name
user_action = rv_user_action
" User Action (C Class Const ACTION_OK, ACTION_OVERWRITE etc)
* file_encoding =
EXCEPTIONS
OTHERS = 0 ).
ENDMETHOD.

ENDCLASS.

CLASS lcl_file_name_dummy IMPLEMENTATION.

METHOD dialog.
ms_file-path = |test.txt|.
rv_user_action = cl_gui_frontend_services=>action_cancel.
ENDMETHOD.

ENDCLASS.

*----------------------------------------------------------------------*
* CLASS lcl_plant_uml IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_plant_uml IMPLEMENTATION.

METHOD constructor.
mv_diagram = iv_diagram.
ENDMETHOD. "constructor

METHOD source.
CLEAR rv_source.
CHECK iv_display_source EQ abap_true.
rv_source = |<p>{ mv_diagram }</p>|.
ENDMETHOD.

METHOD show_html.
cl_abap_browser=>show_html( html_string = iv_html
size = cl_abap_browser=>xlarge
context_menu = abap_true ).
ENDMETHOD.

METHOD output.
CASE is_cfg-output_mode.
WHEN lcl_configuration=>c_mode_url.
show_html( |<img src="{ to_url( ) }"/>\n{ source( is_cfg-display_source ) }| ).

WHEN lcl_configuration=>c_mode_exe.
DATA(lo_name) = lcl_file_name=>new( lcl_file=>c_mode_txt ).
IF lcl_file=>download( iv_data = to_xstring( mv_diagram )
io_name = lo_name ) IS INITIAL.
show_html( |<img src="{ to_png( io_name = lo_name
is_cfg = is_cfg ) }"/>\n{ source( is_cfg-display_source ) }| ).
ENDIF.

WHEN OTHERS.
* export data as PlantUML source
lcl_file=>download( io_name = lcl_file_name=>new( is_cfg-output_mode )
iv_data = to_xstring( mv_diagram ) ).
ENDCASE.
ENDMETHOD. "output

METHOD to_url.
DATA lv_bin TYPE xstring.
* for PlantUML Server: Convert to UTF-8, then deflate, then encode (base64 variant)
cl_abap_gzip=>compress_binary(
EXPORTING
raw_in = to_xstring( mv_diagram ) " UTF-8
compress_level = 9
IMPORTING
gzip_out = lv_bin ).

rv_url = iv_base_url &&
translate( val = cl_http_utility=>encode_x_base64( lv_bin )
from = c_standard
to = c_plantuml ).
ENDMETHOD. "to_url

METHOD to_xstring.
cl_abap_conv_out_ce=>create( encoding = 'UTF-8' )->convert( EXPORTING data = iv_string
IMPORTING buffer = rv_xstring ).
ENDMETHOD. "to_xstring

METHOD parameter_string.
rv_param = |-jar { is_cfg-java_jar } -o { is_cfg-local_path } "{ io_name->get_fullpath( ) }"|.
ENDMETHOD.

METHOD png_file_name.
TRY.
rv_name = |{ is_cfg-local_path }{ io_name->get_prefix( ) }.png|.
CATCH cx_dynamic_check.
CLEAR rv_name.
ENDTRY.
ENDMETHOD.

METHOD to_png.
CLEAR rv_name.
cl_gui_frontend_services=>execute(
EXPORTING application = is_cfg-java_appl
parameter = parameter_string( io_name = io_name
is_cfg = is_cfg )
synchronous = 'X'
EXCEPTIONS OTHERS = 1 ).
IF sy-subrc EQ 0.
rv_name = png_file_name( io_name = io_name
is_cfg = is_cfg ).
ENDIF.
ENDMETHOD.

ENDCLASS. "lcl_plant_uml IMPLEMENTATION

*----------------------------------------------------------------------*
* CLASS lcl_uml_class IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_uml_class IMPLEMENTATION.

METHOD escape.
IF iv_name CA '/'.
rv_name = |"{ iv_name }"|.
ELSE.
rv_name = iv_name.
ENDIF.
ENDMETHOD.

METHOD constructor.
super->constructor( ).
mo_uml = io_uml.
ms_config = is_uml_config.
ENDMETHOD. "constructor

METHOD to_uml_text.
CHECK is_uml-kind CA 'OFP'.
set_data( is_uml ).
plant_uml_class( ).
ENDMETHOD. "to_uml_text

METHOD set_data.
ms_uml = is_uml.
mv_name = get_name( is_uml-name ).
ENDMETHOD. "set_data

METHOD begin_class.
mo_uml->add( |{ get_class( ) } \{\n| ).
ENDMETHOD. "begin_class

METHOD end_class.
mo_uml->add( |\}\n| ).
ENDMETHOD. "end_class

METHOD class_member.
mo_uml->add( |\{static\}| ).
ENDMETHOD. "class_member

METHOD plant_uml_class.
CHECK mv_name IS NOT INITIAL.
begin_class( ).
uml_fields( ).
uml_methods( ).
end_class( ).

IF ms_uml-supertype IS NOT INITIAL.
mo_uml->add( |{ escape( get_name( ms_uml-supertype ) ) } <\|-- { escape( mv_name ) }\n| ).
ENDIF.

uml_reduce( it_data = ms_uml-t_implementations
iv_sep = '-->' ).
uml_reduce( it_data = ms_uml-t_user
iv_sep = '..o'
iv_active = ms_config-show_uses ).
uml_reduce( it_data = ms_uml-t_exceptions
iv_sep = '..'
iv_active = ms_config-show_throws ).
uml_reduce( it_data = ms_uml-t_friends
iv_sep = '..>'
iv_suffix = | : friend |
iv_active = ms_config-show_friends ).
ENDMETHOD. "plant_uml_class

METHOD get_name.
" CHECK substring_before( val = iv_name regex = '\\TYPE=' ) EQ space.
rv_name = substring_after( val = iv_name regex = '\\(CLASS|INTERFACE)=' ).
CHECK rv_name IS INITIAL.
rv_name = substring_after( val = iv_name regex = '\\FUGR=' ).
CHECK rv_name IS NOT INITIAL.
rv_name = rv_name && | <<FUGR>>| .
ENDMETHOD. "get_name

METHOD get_container.
rv_name = substring_after( val = ms_uml-container regex = '\\(CLASS-POOL|PROGRAM|FUNCTION-POOL)=' ).
ENDMETHOD. "get_container

METHOD get_class.
DATA lv_prefix TYPE string.
IF find( val = ms_uml-name sub = '\INTERFACE=' ) GE 0.
lv_prefix = |interface|.
ELSEIF ms_uml-is_abstract IS NOT INITIAL.
lv_prefix = |abstract class|.
ELSE.
lv_prefix = |class|.
ENDIF.
rv_class = |{ lv_prefix } { mv_name }|.
IF ms_uml-container IS NOT INITIAL AND ms_uml-is_local EQ abap_true.
rv_class = |{ lv_prefix } "{ mv_name }\\n({ get_container( ) })" as { mv_name }|.
ENDIF.
ENDMETHOD. "get_class

METHOD visibility.
CONSTANTS:
c_vis_package TYPE char01 VALUE 'I',
c_vis_private TYPE char01 VALUE 'P',
c_vis_protected TYPE char01 VALUE 'O',
c_vis_public TYPE char01 VALUE 'U'.

DATA lv_vis TYPE char01.

CASE iv_visibility.
WHEN c_vis_private. lv_vis = '-'.
WHEN c_vis_protected. lv_vis = '#'.
WHEN c_vis_package. lv_vis = '~'.
WHEN c_vis_public. lv_vis = '+'.
ENDCASE.
mo_uml->add( |{ lv_vis }| ).
ENDMETHOD. "visibility

METHOD uml_add.
IF iv_abstract EQ abap_true.
mo_uml->add( |\{abstract\}| ).
ENDIF.
visibility( iv_visibility ).
IF iv_class EQ abap_true.
class_member( ).
ENDIF.
mo_uml->add( |{ iv_name }\n| ).
ENDMETHOD. "uml_add

METHOD uml_reduce.
FIELD-SYMBOLS <lv_line> TYPE csequence.

CHECK iv_active EQ abap_true.
LOOP AT it_data ASSIGNING <lv_line>.
mo_uml->add( |{ escape( mv_name ) } { iv_sep } { escape( get_name( <lv_line> ) ) }{ iv_suffix }\n| ).
ENDLOOP.
ENDMETHOD. "uml_reduce

METHOD uml_events.
* mo_uml->add( |{ mv_name } ..o { get_name( ls_event-name ) }\n| ).
LOOP AT ms_uml-t_events INTO DATA(ls_event).
uml_add( iv_visibility = ls_event-visibility
iv_class = ls_event-is_static
iv_name = |{ ls_event-name }( )| ).
ENDLOOP.
ENDMETHOD. "uml_events

METHOD uml_fields.
LOOP AT ms_uml-t_attributes INTO DATA(ls_field) WHERE is_constant EQ space.
uml_add( iv_visibility = ls_field-visibility
iv_class = ls_field-is_class
iv_name = ls_field-name ).
ENDLOOP.
ENDMETHOD. "uml_fields

METHOD uml_methods.
LOOP AT ms_uml-t_methods INTO DATA(ls_method).
uml_add( iv_abstract = ls_method-is_abstract
iv_visibility = ls_method-visibility
iv_class = ls_method-is_class
iv_name = |{ ls_method-name }( )| ).
ENDLOOP.
ENDMETHOD. "uml_methods

ENDCLASS. "lcl_uml_class IMPLEMENTATION

*----------------------------------------------------------------------*
* CLASS lcl_class_diagram IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_class_diagram IMPLEMENTATION.

METHOD generate.
rv_diagram = NEW lcl_class_diagram( it_uml )->to_uml_text( is_output_config = is_output_config
is_uml_config = is_uml_config ).
ENDMETHOD. "generate

METHOD to_uml_text.
DATA(lo_uml) = lcl_uml=>new( is_output_config ).
DATA(lo_class) = NEW lcl_uml_class( io_uml = lo_uml
is_uml_config = is_uml_config ).
WHILE has_next( ).
lo_class->to_uml_text( next( ) ).
ENDWHILE.

rv_diagram = lo_uml->get( ).
ENDMETHOD. "to_uml_text

ENDCLASS. "lcl_class_diagram IMPLEMENTATION

*----------------------------------------------------------------------*
* CLASS lcl_uml IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_uml IMPLEMENTATION.

METHOD new.
ro_uml = NEW #( ).
ro_uml->header( is_cfg ).
ENDMETHOD. "new

METHOD add.
mv_diagram = mv_diagram && iv_code.
ENDMETHOD. "add

METHOD get.
footer( ).
rv_diagram = mv_diagram.
ENDMETHOD. "get

METHOD header.
add( |@startuml\n| ). " Header
add( |scale { is_cfg-scale }\n| ). " Reduce the size of the output image
ENDMETHOD. "header

METHOD footer.
add( |hide <<FUGR>> circle\n| ).
add( |@enduml\n| ).
ENDMETHOD. "footer

ENDCLASS. "lcl_uml IMPLEMENTATION

*----------------------------------------------------------------------*
* CLASS lcl_iterator IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_iterator IMPLEMENTATION.

METHOD constructor.
CLEAR mv_idx.
mt_data = it_data. " never changed
IF iv_stop IS INITIAL.
mv_size = lines( mt_data ).
ELSE.
mv_size = iv_stop.
ENDIF.
skip( iv_start - 1 ).
ENDMETHOD. "constructor

METHOD next.
skip( ).
rs_uml = mt_data[ mv_idx ].
ENDMETHOD. "next

METHOD has_next.
rv_flag = xsdbool( mv_idx < mv_size ).
ENDMETHOD. "has_next

METHOD skip.
ADD iv_count TO mv_idx.
ENDMETHOD. "skip

ENDCLASS. "lcl_iterator IMPLEMENTATION

*----------------------------------------------------------------------*
* CLASS lcl_xmi_output IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_xmi_output IMPLEMENTATION.

METHOD new_xmi.
ro_xmi = NEW cl_uml_class_decor_xmi( io_scanner ).

DATA(ls_scan) = ii_parameter->get_scan_config( ).
ro_xmi->set_decorator_configuration( attributes = ls_scan-attributes
methods = ls_scan-methods
constants = ls_scan-constants
private_member = ls_scan-private_member
protected_member = ls_scan-protected_member
packaged_member = ls_scan-packaged_member ).
DATA(ls_cfg) = ii_parameter->get_display_config( ).
ro_xmi->set_xmi_configuration( aggregations = ls_cfg-show_aggregations
associations = ls_cfg-show_associations
uses = ls_cfg-show_uses
friends = ls_cfg-show_friends
show_exceptions = ls_cfg-show_throws ).
ENDMETHOD. "lif_parameter~new_xmi

METHOD lif_output~output.
DATA lr_data TYPE REF TO data.
FIELD-SYMBOLS <lv_data> TYPE xstring.

rv_flag = abap_false.
DATA(lo_scanner) = NEW lcl_scanner( ii_parameter ).

CHECK lo_scanner->class_scan( ).
new_xmi( io_scanner = lo_scanner
ii_parameter = ii_parameter )->get_diagram( CHANGING c_data = lr_data ).
ASSIGN lr_data->* TO <lv_data> CASTING.
CHECK <lv_data> IS ASSIGNED.

lcl_file=>download( iv_data = <lv_data>
io_name = lcl_file_name=>new( lcl_file=>c_mode_xmi ) ).
rv_flag = abap_true.
ENDMETHOD. "lif_output~output

ENDCLASS. "lcl_xmi_output IMPLEMENTATION

*----------------------------------------------------------------------*
* CLASS lcl_plantuml_output IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_plantuml_output IMPLEMENTATION.

METHOD lif_output~output.
DATA lr_data TYPE REF TO data.
DATA lr_uml_tab TYPE REF TO cl_uml_class_scanner=>uml_tab.

rv_flag = abap_false.
DATA(lo_scanner) = NEW lcl_scanner( ii_parameter ).

CHECK lo_scanner->class_scan( ).
"DATA lv_kind TYPE c VALUE cl_uml_class_scanner=>c_kind_uml_tab.
lo_scanner->get_diagram( "IMPORTING e_kind = lv_kind
CHANGING c_data = lr_data ).
TRY.
lr_uml_tab ?= lr_data.
CHECK lr_uml_tab IS BOUND.
DATA(ls_cfg) = lcl_configuration=>get( ).
NEW lcl_plant_uml( lcl_class_diagram=>generate( it_uml = lr_uml_tab->*
is_uml_config = ii_parameter->get_display_config( )
is_output_config = ls_cfg )
)->output( ls_cfg ).
rv_flag = abap_true.
CATCH cx_dynamic_check. "#EC NO_HANDLER
ENDTRY.
ENDMETHOD. "lif_output~output

ENDCLASS. "lcl_plantuml_output IMPLEMENTATION

CLASS lcl_null_output IMPLEMENTATION.

METHOD lif_output~output.
rv_flag = abap_false.
ENDMETHOD.

ENDCLASS.

CLASS lcl_configuration IMPLEMENTATION.

METHOD class_constructor.
gs_cfg = VALUE #( java_appl = get_java_path( )
* PlantUML jar file and output path
local_path = `C:\Temp\Dokumente\UML\`
java_jar = `C:\Temp\Dokumente\UML\plantuml.jar`
* PlantUML server URL
server_url = `http://www.plantuml.com/plantuml/img/` ##NO_TEXT
output_mode = c_mode_url
skip_dialog = space
scale = c_default_scale
handwritten = abap_false
shadowing = abap_false
display_source = abap_true ).
* Windows: Local Java installation
IF gs_cfg-java_appl IS INITIAL.
gs_cfg-java_appl = `C:\Windows\System32\java`.
ENDIF.
ENDMETHOD.

METHOD get_java_path.
CONSTANTS c_registry_java_base_key TYPE string
VALUE 'SOFTWARE\JavaSoft\Java Runtime Environment' ##NO_TEXT.
DATA lv_path TYPE string.

CLEAR rv_fullpath.
cl_gui_frontend_services=>registry_get_value(
EXPORTING
root = cl_gui_frontend_services=>hkey_local_machine
key = c_registry_java_base_key
value = 'CurrentVersion'
IMPORTING
reg_value = lv_path
EXCEPTIONS
OTHERS = 5 ).
CHECK sy-subrc EQ 0.
cl_gui_frontend_services=>registry_get_value(
EXPORTING
root = cl_gui_frontend_services=>hkey_local_machine
key = |{ c_registry_java_base_key }\\{ lv_path }|
value = 'JavaHome'
IMPORTING
reg_value = lv_path
EXCEPTIONS
OTHERS = 5 ).
CHECK sy-subrc EQ 0.
rv_fullpath = |{ lv_path }\\bin\\java|.
ENDMETHOD.

METHOD get_attributes.
DEFINE fill_att.
INSERT VALUE #( ref = REF #( &1 )
text = &2
kind = &3 ) INTO TABLE rt_attr.
END-OF-DEFINITION.
DEFINE fill_radio.
INSERT VALUE #( ref = REF #( &1 )
text = &2
kind = 'R'
button_group = &3 ) INTO TABLE rt_attr.
END-OF-DEFINITION.
* Table Type has type 'T' - patterns SCI_PATTERN
* ' ' - ?? private attributes?
* 'I' - ?? Integer?
fill_att gs_cfg-skip_dialog 'Remember my settings'(c00) 'C'.

fill_att: sy-index 'PlantUML Execution Mode'(c10) 'G'. " Group
fill_radio: mv_mode_url 'PlantUML web service'(c11) 'MOD',
mv_mode_txt 'Save text file'(c12) 'MOD',
mv_mode_exe 'Local PlantUML '(c13) 'MOD'.

fill_att: '' 'PlantUML Settings'(c20) 'G',
gs_cfg-scale 'Scale '(c21) 'S'.
fill_att: gs_cfg-server_url 'PlantUML Server'(c25) 'S',
gs_cfg-local_path 'Local PlantUML path'(c26) 'S',
gs_cfg-java_jar 'Local PlantUML jar file'(c27) ' ',
gs_cfg-java_appl 'Local Java path'(c28) 'S'. " Select-Options
fill_att: gs_cfg-handwritten 'Handwritten '(c30) 'C',
gs_cfg-shadowing 'Shadowing '(c31) 'C',
gs_cfg-display_source 'Display source '(c32) 'C'.
ENDMETHOD.

METHOD to_radiobutton.
mv_mode_url = xsdbool( gs_cfg-output_mode EQ c_mode_url ).
mv_mode_exe = xsdbool( gs_cfg-output_mode EQ c_mode_exe ).
mv_mode_txt = xsdbool( gs_cfg-output_mode EQ c_mode_txt ).
ENDMETHOD.

METHOD from_radiobutton.
IF mv_mode_url EQ abap_true.
gs_cfg-output_mode = c_mode_url.
ELSEIF mv_mode_exe EQ abap_true.
gs_cfg-output_mode = c_mode_exe.
ELSEIF mv_mode_txt EQ abap_true.
gs_cfg-output_mode = c_mode_txt.
ENDIF.
ENDMETHOD.

METHOD get.
rs_cfg = CORRESPONDING #( gs_cfg ).
ENDMETHOD.

METHOD query.
DATA(lo_config) = NEW lcl_configuration( ).
lo_config->dialog( ).
rs_cfg = lo_config->get( ).
ENDMETHOD.

METHOD dialog.
to_radiobutton( ).
CHECK gs_cfg-skip_dialog EQ abap_false.
CHECK cl_ci_query_attributes=>generic(
p_name = CONV #( sy-repid ) " unique screen ID
p_title = 'Class Diagram Parameters' " Screen title
p_attributes = get_attributes( ) " Screen fields
p_display = abap_false " Edit / Display only
) EQ abap_false. " Do not cancel
from_radiobutton( ).
ENDMETHOD.

ENDCLASS.

*----------------------------------------------------------------------*
* CLASS lcl_app IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_app IMPLEMENTATION.

METHOD init.
button1 = text-007.
button2 = text-008.
button3 = text-009.
* pushbutton in the application toolbar
sscrfields-functxt_01 = VALUE smp_dyntxt( icon_id = '@4Y@' " ICON_BUSINAV_ENTITY
icon_text = text-p01 " PlantUML
quickinfo = text-p01
text = text-p01 ).
sscrfields-functxt_02 = VALUE smp_dyntxt( icon_id = '@BX@' " ICON_CONFIGURATION
icon_text = text-p02 " PlantUML Configuration
quickinfo = text-p02
text = text-p02 ).
ENDMETHOD.

METHOD user_command.
DATA li_export TYPE REF TO lif_output.

CASE iv_ucomm.
WHEN 'FC01'.
* PlantUML Output
li_export = NEW lcl_plantuml_output( ).
WHEN 'ONLI'.
li_export = NEW lcl_xmi_output( ).
WHEN 'FC02'.
lcl_configuration=>query( ).
rv_flag = abap_true.
RETURN.
WHEN OTHERS.
li_export = NEW lcl_null_output( ).
ENDCASE.

rv_flag = li_export->output( NEW lcl_parameter( iv_progname = sy-repid ) ).
ENDMETHOD. "execute

ENDCLASS. "lcl_app IMPLEMENTATION

" ----------------------------------------------------------------------------------------------------------------------------------- *
" program events

INITIALIZATION.
lcl_app=>init( ).

AT SELECTION-SCREEN.
IF lcl_app=>user_command( sscrfields-ucomm ).
CLEAR sscrfields-ucomm.
ENDIF.

START-OF-SELECTION.
lcl_app=>user_command( sy-ucomm ).
15 Comments