├── src
├── .gitkeep
├── zz_lisp_ide.prog.abap
├── package.devc.xml
├── yy_lib_turtle.prog.xml
├── yy_lib_registry.prog.xml
├── yy_lisp_turtle.prog.xml
├── zz_registry_test.prog.xml
├── zz_registry_browser.prog.xml
├── zcl_lisp_area.shma.xml
├── yy_lib_lisp.prog.xml
├── yy_lisp_aunit.prog.xml
├── yy_lisp_ide.prog.xml
├── yjn_script_sexpr_view.prog.xml
├── zcl_lisp_shm_root.clas.xml
├── zcl_lisp_shm_root.clas.abap
├── zz_registry_test.prog.abap
├── yjn_script_sexpr_view.prog.abap
├── yy_lisp_turtle.prog.abap
├── zz_lisp_ide.prog.xml
├── zcl_lisp_area.clas.xml
├── yy_lib_registry.prog.abap
├── zz_registry_browser.prog.abap
├── yy_lib_turtle.prog.abap
└── zcl_lisp_area.clas.abap
├── _config.yml
├── img
├── sexpr_new.PNG
├── AUnit_Tests.png
├── new_editor.png
├── sample_sexp.png
├── zz_lisp_uml.png
├── default_editor.png
├── lisplogo_256.png
├── popular_blogs.png
├── abap_lisp_trace.png
├── sample_sexp_new.PNG
├── SExpressionViewer.png
├── abap_lisp_workbench.png
├── lisplogo_fancy_128.png
└── abap_scheme_workbench.png
├── .travis.yml
├── .abapgit.xml
├── abaplint.json
├── LICENSE
├── .github
└── workflows
│ └── abaplint.yml
├── editor
├── lisp_user.xml
├── README.md
└── lisp_spec.xml
└── README.md
/src/.gitkeep:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/img/sexpr_new.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/sexpr_new.PNG
--------------------------------------------------------------------------------
/img/AUnit_Tests.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/AUnit_Tests.png
--------------------------------------------------------------------------------
/img/new_editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/new_editor.png
--------------------------------------------------------------------------------
/img/sample_sexp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/sample_sexp.png
--------------------------------------------------------------------------------
/img/zz_lisp_uml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/zz_lisp_uml.png
--------------------------------------------------------------------------------
/img/default_editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/default_editor.png
--------------------------------------------------------------------------------
/img/lisplogo_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/lisplogo_256.png
--------------------------------------------------------------------------------
/img/popular_blogs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/popular_blogs.png
--------------------------------------------------------------------------------
/img/abap_lisp_trace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/abap_lisp_trace.png
--------------------------------------------------------------------------------
/img/sample_sexp_new.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/sample_sexp_new.PNG
--------------------------------------------------------------------------------
/img/SExpressionViewer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/SExpressionViewer.png
--------------------------------------------------------------------------------
/img/abap_lisp_workbench.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/abap_lisp_workbench.png
--------------------------------------------------------------------------------
/img/lisplogo_fancy_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/lisplogo_fancy_128.png
--------------------------------------------------------------------------------
/img/abap_scheme_workbench.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomssi/abap_scheme/HEAD/img/abap_scheme_workbench.png
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "10"
4 | notifications:
5 | email: false
6 | before_script:
7 | - npm install -g abaplint
8 | script:
9 | - abaplint "src/**/*.*"
10 | branches:
11 | only:
12 | - Netweaver-7.52
13 | - master
14 |
--------------------------------------------------------------------------------
/src/zz_lisp_ide.prog.abap:
--------------------------------------------------------------------------------
1 | REPORT zz_lisp_ide.
2 |
3 | INCLUDE yy_lib_lisp.
4 |
5 | INCLUDE yy_lisp_turtle.
6 | INCLUDE yy_lisp_aunit.
7 | INCLUDE yy_lisp_ide.
8 |
9 | INITIALIZATION.
10 | lcl_ide=>init( ).
11 |
12 | START-OF-SELECTION.
13 | lcl_ide=>main( ).
14 |
--------------------------------------------------------------------------------
/src/package.devc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ABAP Scheme
7 | CA
8 | HLB0009110
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/yy_lib_turtle.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | YY_LIB_TURTLE
7 | I
8 | *
9 | K
10 | E
11 | X
12 |
13 |
14 | -
15 | R
16 | Include YY_LIB_TURTLE
17 | 21
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/yy_lib_registry.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | YY_LIB_REGISTRY
7 | I
8 | *
9 | K
10 | E
11 | X
12 |
13 |
14 | -
15 | R
16 | Include YY_LIB_REGISTRY
17 | 23
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/yy_lisp_turtle.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | YY_LISP_TURTLE
7 | I
8 | *
9 | K
10 | E
11 | X
12 |
13 |
14 | -
15 | R
16 | Include YY_LISP_TURTLE
17 | 22
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/zz_registry_test.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZZ_REGISTRY_TEST
7 | 1
8 | *
9 | K
10 | E
11 | X
12 | X
13 |
14 |
15 | -
16 | R
17 | Program ZZ_REGISTRY_TEST
18 | 24
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.abapgit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | E
6 | /src/
7 | PREFIX
8 |
9 | - /.gitignore
10 | - /LICENSE
11 | - /README.md
12 | - /package.json
13 | - /.travis.yml
14 | - /_config.yml
15 | - /img/abap_lisp_workbench.png
16 | - /src/.gitkeep
17 | - /abaplint.json
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/zz_registry_browser.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZZ_REGISTRY_BROWSER
7 | 1
8 | *
9 | K
10 | E
11 | X
12 | X
13 |
14 |
15 | -
16 | R
17 | Report ZZ_REGISTRY_BROWSER
18 | 26
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/zcl_lisp_area.shma.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_LISP_AREA
7 | ABAP Lisp Workbench - Shared Area
8 | ZCL_LISP_SHM_ROOT
9 | X
10 | X
11 | ZCL_LISP_SHM_ROOT
12 | 109200001
13 | 159200000
14 | 1208200200
15 | 1107197102
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/yy_lib_lisp.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | YY_LIB_LISP
7 | I
8 | *
9 | K
10 | E
11 | X
12 |
13 |
14 | -
15 | R
16 | ABAP Scheme
17 | 18
18 |
19 |
20 |
21 | -
22 | D
23 |
24 |
-
25 | R
26 | 18
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/yy_lisp_aunit.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | YY_LISP_AUNIT
7 | I
8 | *
9 | K
10 | E
11 | X
12 |
13 |
14 | -
15 | R
16 | ABAP Scheme ABAP Unit Test Suite
17 | 37
18 |
19 |
20 |
21 | -
22 | D
23 |
24 |
-
25 | R
26 | 18
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/yy_lisp_ide.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | YY_LISP_IDE
7 | I
8 | *
9 | K
10 | E
11 | X
12 |
13 |
14 | -
15 | R
16 | ABAP Scheme Workbench
17 | 21
18 |
19 |
20 |
21 | -
22 | D
23 |
24 |
-
25 | R
26 | Include YY_LISP_IDE
27 | 19
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/yjn_script_sexpr_view.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | YJN_SCRIPT_SEXPR_VIEW
7 | S
8 | S
9 | X
10 | X
11 | D$S
12 | X
13 |
14 |
15 | -
16 | R
17 | 23
18 |
19 |
20 |
21 | -
22 | D
23 |
24 |
-
25 | R
26 | S-Expression Viewer
27 | 19
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/zcl_lisp_shm_root.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_LISP_SHM_ROOT
7 | E
8 | ABAP Lisp: Shared Memory Puffer
9 | 1
10 | X
11 | X
12 | X
13 | K
14 | X
15 |
16 |
17 |
18 | LOAD
19 | E
20 | Save Information for Personalization
21 |
22 |
23 | SAVE
24 | E
25 | Retrieve Information for Personalization
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/abaplint.json:
--------------------------------------------------------------------------------
1 | {
2 | "global": {
3 | "files": "/src/**/*.*",
4 | "skipGeneratedGatewayClasses": true,
5 | "skipGeneratedPersistentClasses": true,
6 | "skipGeneratedFunctionGroups": true
7 | },
8 | "dependencies": [
9 | {
10 | "url": "https://github.com/abaplint/deps",
11 | "folder": "/deps",
12 | "files": "/src/**/*.*"
13 | }
14 | ],
15 | "syntax": {
16 | "version": "v740sp08",
17 | "errorNamespace": "^(Z|Y)",
18 | "globalConstants": [],
19 | "globalMacros": []
20 | },
21 | "rules": {
22 | "line_length": false,
23 | "contains_tab": false,
24 | "functional_writing": false,
25 | "max_one_statement": true,
26 | "parser_error": false,
27 | "space_before_colon": true,
28 | "colon_missing_space": true,
29 | "exit_or_check": false,
30 | "obsolete_statement": false,
31 | "start_at_tab": false,
32 | "whitespace_end": true,
33 | "exporting": true,
34 | "empty_statement": true,
35 | "sequential_blank": {
36 | "lines":4
37 | },
38 | "definitions_top": false
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Jacques Nomssi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/workflows/abaplint.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: CI
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the master branch
8 | push:
9 | branches: [ master ]
10 | pull_request:
11 | branches: [ master ]
12 |
13 | # Allows you to run this workflow manually from the Actions tab
14 | workflow_dispatch:
15 |
16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
17 | jobs:
18 | # This workflow contains a single job called "abaplint"
19 | build:
20 | # The type of runner that the job will run on
21 | runs-on: ubuntu-latest
22 |
23 | # Steps represent a sequence of tasks that will be executed as part of the job
24 | steps:
25 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
26 | - uses: actions/checkout@v2
27 |
28 | # Runs a command using the runners shell
29 | - name: abaplint
30 | uses: abaplint/actions-abaplint@main
31 | env:
32 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33 |
--------------------------------------------------------------------------------
/editor/lisp_user.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Jacques Nomssi
6 | LangUser
7 | LISP
8 | User specific settings for Scheme
9 |
10 |
11 |
12 | cond Conditionals
13 | (cond ((<test1>) <expression11> ... )\n ((<test2>) <expression21> ... )\n (else <expressionN1> ... )
14 |
15 |
16 | ;;;-----
17 | ;;;-------------------------------------------------------------------
18 |
19 |
20 | (define ...)
21 | (define \n%SurroundedText%\n )
22 |
23 |
24 | (let ...) binding
25 | (let ((<variable1> <init1>)\n ( <variableN> <initN>) )\n <body>)
26 |
27 |
28 | ;-------...
29 |
30 |
31 | (if ...) Conditional(if <test> \n <consequent>\n <alternate> )procedure(lambda (<formals>)\n (<body>))(do ...) Iteration(do (<variable1> <init1> <step1>)\n ... )\n (<test> <expression> ... )\n <command> ... )(begin ...) sequencing(begin ... )
32 |
33 |
--------------------------------------------------------------------------------
/src/zcl_lisp_shm_root.clas.abap:
--------------------------------------------------------------------------------
1 | class ZCL_LISP_SHM_ROOT definition
2 | public
3 | final
4 | create public
5 | shared memory enabled .
6 |
7 | public section.
8 |
9 | interfaces IF_SHM_BUILD_INSTANCE .
10 |
11 | types:
12 | BEGIN OF ts_settings,
13 | stack TYPE string_table,
14 | new_editor TYPE flag,
15 | END OF ts_settings .
16 | types:
17 | BEGIN OF ts_param.
18 | INCLUDE TYPE ts_settings as settings.
19 | TYPES: uname TYPE syuname,
20 | datum TYPE aedat,
21 | uzeit TYPE uzeit,
22 | END OF ts_param .
23 |
24 | methods LOAD
25 | importing
26 | !IV_UNAME type SYUNAME default SY-UNAME
27 | returning
28 | value(RS_SETTINGS) type TS_SETTINGS .
29 | methods SAVE
30 | importing
31 | !IV_UNAME type SYUNAME default SY-UNAME
32 | !IS_SETTINGS type TS_SETTINGS .
33 | PROTECTED SECTION.
34 | PRIVATE SECTION.
35 | DATA ms_param TYPE ts_param.
36 | ENDCLASS.
37 |
38 |
39 |
40 | CLASS ZCL_LISP_SHM_ROOT IMPLEMENTATION.
41 |
42 |
43 | METHOD if_shm_build_instance~build.
44 | DATA params TYPE REF TO zcl_lisp_shm_root.
45 | DATA handle TYPE REF TO zcl_lisp_area.
46 |
47 | handle = zcl_lisp_area=>attach_for_write( ).
48 | CREATE OBJECT params AREA HANDLE handle.
49 | handle->set_root( params ).
50 | * Initial values are saved
51 | handle->detach_commit( ).
52 |
53 | ENDMETHOD.
54 |
55 |
56 | METHOD LOAD.
57 | rs_settings = ms_param-settings.
58 | ENDMETHOD.
59 |
60 |
61 | METHOD SAVE.
62 | ms_param = VALUE #( settings = is_settings
63 | uname = iv_uname
64 | datum = sy-datum
65 | uzeit = sy-uzeit ).
66 | ENDMETHOD.
67 | ENDCLASS.
68 |
--------------------------------------------------------------------------------
/src/zz_registry_test.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Report ZZ_REGISTRY_TEST
3 | *&---------------------------------------------------------------------*
4 | *& Author: Martin Ceronio (2015), http://ceronio.net
5 | *& Released under MIT License: http://opensource.org/licenses/MIT
6 | *& All modifications by JNN
7 | *&---------------------------------------------------------------------*
8 | REPORT zz_registry_test.
9 | * Make the registry API available to our program
10 |
11 | INCLUDE yy_lib_registry.
12 |
13 | DATA reg_entry TYPE REF TO lcl_registry_entry.
14 | DATA lv_customer TYPE kunnr.
15 | DATA lv_run_date TYPE d.
16 | DATA lv_timestamp TYPE timestamp.
17 |
18 | START-OF-SELECTION.
19 | * Get the root entry of the registry
20 | DATA(reg_root) = lcl_registry_entry=>get_root( ).
21 |
22 | * If we want to ensure, on startup, that a certain entry exists, we
23 | * could do the following (e.g. in LOAD-OF-PROGRAM):
24 | reg_root->create_by_path( 'Sales/Enhancements/Process_XYZ' ).
25 |
26 | * Retrieval of a specific entry. If we did not have the above line,
27 | * we would have to check that the result of each call to GET_SUBENTRY( )
28 | * to ensure it is bound.
29 | reg_entry = reg_root->get_subentry( 'Sales' )->get_subentry( 'Enhancements' )->get_subentry( 'Process_XYZ' ).
30 |
31 | * Getting a specific value from the entry:
32 | lv_customer = reg_entry->get_value( 'Process_XYZ' ).
33 | "lv_customer = reg_entry->get_value( 'Process_XYZCustomer' ).
34 |
35 | * Writing values to the entry:
36 | lv_run_date = sy-datum.
37 | reg_entry->set_value( key = 'LastRunDate' value = lv_run_date ).
38 | GET TIME STAMP FIELD lv_timestamp.
39 | reg_entry->set_value( key = 'LastRunDateTime' value = lv_timestamp ).
40 |
41 | * Saving the entry
42 | reg_entry->save( ).
43 |
--------------------------------------------------------------------------------
/editor/README.md:
--------------------------------------------------------------------------------
1 | # ABAP Editor Configuration
2 |
3 | ## Default ABAP Scheme Workbench Editor
4 | 
5 |
6 | ## How To Enable The New ABAP Editor
7 | The SAP GUI ABAP Editor for LISP enables
8 | * syntax highlighting
9 | * code completion
10 |
11 | 
12 |
13 | ## SAP GUI Configuration Folder
14 |
15 | The SAP GUI configuration files are located in the roaming user application directory. They can be reached using the environment variable %APPDATA%.
16 |
17 | cd %APPDATA%\SAP\SAP GUI\ABAP Editor
18 | Windows 10 => [ C:\Users\\AppData\Roaming\SAP\SAP GUI\ABAP Editor ]
19 |
20 | ## Configuration Steps
21 | 1. You must manually copy two configuration files provided here in your local SAP GUI configuration folder for the ABAP Editor
22 |
23 | * lisp_spec.xml
24 | * lisp_user.xml
25 |
26 | 2. Change in the first lines of ABAP Include YY_LISP_IDE
27 |
28 | c_new_abap_editor TYPE flag VALUE abap_true,
29 | c_source_type TYPE string VALUE 'LISP'.
30 |
31 | 3. Restart the workbench.
32 |
33 | ## Configuration Files
34 |
35 | To create your own theme files
36 |
37 | * lisp_spec.xml
38 | * lisp_user.xml
39 |
40 | read
41 |
42 | * https://wiki.scn.sap.com/wiki/display/NWTech/SAP+GUI+Logon+Configuration
43 | * https://github.com/lucattelli/ab4-themes
44 | * https://github.com/alexey-arseniev/ab4-code-templates
45 | * https://blogs.sap.com/2017/08/01/old-new-abap-editor/
46 |
47 | The comments in the blog post
48 |
49 | * https://blogs.sap.com/2015/06/24/a-lisp-interpreter-in-abap/
50 |
51 | give useful hints:
52 |
53 | In lisp_spec.xml,
54 |
55 | add
56 |
57 |
58 | …
59 |
60 |
61 |
62 | …
63 |
64 |
65 |
66 |
67 | >
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/yjn_script_sexpr_view.prog.abap:
--------------------------------------------------------------------------------
1 | *
2 | REPORT rstpda_script_template.
3 |
4 | *
5 | *RSTPDA_SCRIPT_TEMPLATE
6 | *LCL_DEBUGGER_SCRIPT
7 | *Debugger Skript: Default Template
8 | *X
9 |
10 | *
11 |
12 | *
13 |
14 | *
15 |
16 | *
17 | *---------------------------------------------------------------------*
18 | * CLASS lcl_debugger_script DEFINITION
19 | *---------------------------------------------------------------------*
20 | *
21 | *---------------------------------------------------------------------*
22 | CLASS lcl_debugger_script DEFINITION INHERITING FROM cl_tpda_script_class_super .
23 |
24 | PUBLIC SECTION.
25 | METHODS: prologue REDEFINITION,
26 | init REDEFINITION,
27 | script REDEFINITION,
28 | end REDEFINITION.
29 |
30 | ENDCLASS. "lcl_debugger_script DEFINITION
31 | *---------------------------------------------------------------------*
32 | * CLASS lcl_debugger_script IMPLEMENTATION
33 | *---------------------------------------------------------------------*
34 | *
35 | *---------------------------------------------------------------------*
36 | CLASS lcl_debugger_script IMPLEMENTATION.
37 | METHOD prologue.
38 | *** generate abap_source (source handler for ABAP)
39 | super->prologue( ).
40 | ENDMETHOD. "prolog
41 |
42 | METHOD init.
43 | *** insert your initialization code here
44 | ENDMETHOD. "init
45 | METHOD script.
46 |
47 | *** insert your script code here
48 | me->break( ).
49 |
50 | ENDMETHOD. "script
51 | METHOD end.
52 | *** insert your code which shall be executed at the end of the scripting (before trace is saved)
53 | *** here
54 |
55 | ENDMETHOD. "end
56 | ENDCLASS. "lcl_debugger_script IMPLEMENTATION
57 | *
58 |
59 | *
60 |
--------------------------------------------------------------------------------
/src/yy_lisp_turtle.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Include YY_LISP_TURTLE
3 | *&---------------------------------------------------------------------*
4 | * Ported from https://github.com/FreHu/abap-turtle-graphics
5 |
6 | CLASS lcl_turtle_examples DEFINITION.
7 | PUBLIC SECTION.
8 | CLASS-METHODS polygon_flower
9 | IMPORTING polygons TYPE tv_int
10 | polygon_sides TYPE tv_int
11 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
12 |
13 | CLASS-METHODS filled_square
14 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
15 |
16 | CLASS-METHODS polygon_using_lines
17 | IMPORTING num_sides TYPE tv_int
18 | side_length TYPE tv_int
19 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
20 |
21 | PRIVATE SECTION.
22 | CLASS-METHODS demo IMPORTING title TYPE string OPTIONAL
23 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
24 | ENDCLASS.
25 |
26 | CLASS lcl_turtle_examples IMPLEMENTATION.
27 |
28 | METHOD demo.
29 | turtle = lcl_turtle=>new( height = 800 width = 800 title = title ).
30 | turtle->goto( x = 200 y = 200 ).
31 |
32 | turtle->set_pen( VALUE #(
33 | fill_color = `#FF0000`
34 | stroke_color = `#FF00FF`
35 | stroke_width = 2 ) ).
36 | ENDMETHOD.
37 |
38 | METHOD filled_square.
39 | turtle = demo( )->filled_square( side_length = 100
40 | start = VALUE lcl_turtle=>t_point( x = 100 y = 100 ) ).
41 | ENDMETHOD.
42 |
43 | METHOD polygon_flower.
44 | turtle = demo( title = |Polygons:{ polygons } Sides: { polygon_sides }|
45 | )->polygon_flower( number_of_polygons = polygons
46 | polygon_sides = polygon_sides
47 | side_length = 50 ).
48 | ENDMETHOD.
49 |
50 | METHOD polygon_using_lines.
51 | turtle = demo( )->regular_polygon( num_sides = num_sides
52 | side_length = side_length ).
53 | ENDMETHOD.
54 | ENDCLASS.
55 |
56 | CLASS lcl_turtle_lsystem_examples DEFINITION.
57 | PUBLIC SECTION.
58 | CLASS-METHODS koch_curve.
59 | CLASS-METHODS pattern.
60 | CLASS-METHODS plant.
61 | CLASS-METHODS plant_2.
62 | PRIVATE SECTION.
63 | CLASS-METHODS execute IMPORTING title TYPE string OPTIONAL
64 | x TYPE tv_int DEFAULT 200
65 | y TYPE tv_int DEFAULT 200
66 | angle TYPE tv_real OPTIONAL
67 | parameters TYPE lcl_turtle_lsystem=>params.
68 | ENDCLASS.
69 |
70 | CLASS lcl_turtle_lsystem_examples IMPLEMENTATION.
71 |
72 | METHOD execute.
73 | DATA(turtle) = lcl_turtle=>new( height = 800 width = 600 title = title ).
74 | turtle->goto( x = x
75 | y = y ).
76 | turtle->set_angle( angle ).
77 |
78 | DATA(lsystem) = lcl_turtle_lsystem=>new( turtle = turtle
79 | parameters = parameters ).
80 | lsystem->execute( ).
81 | lsystem->show( ).
82 | ENDMETHOD.
83 |
84 | METHOD koch_curve.
85 | execute( title = |Koch curve|
86 | parameters = lcl_turtle_lsystem=>koch_curve_params( ) ).
87 | ENDMETHOD.
88 |
89 |
90 | METHOD pattern.
91 | execute( parameters = lcl_turtle_lsystem=>pattern_params( ) ).
92 | ENDMETHOD.
93 |
94 | METHOD plant.
95 | execute( x = 300
96 | y = 600
97 | angle = -90
98 | parameters = lcl_turtle_lsystem=>plant_params( ) ).
99 | ENDMETHOD.
100 |
101 | METHOD plant_2.
102 | execute( x = 300
103 | y = 600
104 | angle = -90
105 | parameters = lcl_turtle_lsystem=>plant_2_params( ) ).
106 | ENDMETHOD.
107 |
108 | ENDCLASS.
109 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ABAP Scheme
2 | [](https://www.sap.com/developer/topics/abap-platform.html)
3 | [](https://opensource.org/licenses/MIT)
4 |
5 | - is an interpreter for Scheme, a Lisp dialect with exceptionally clear and concise semantics and a focus on functional programming
6 | - provides a SAP GUI based workbench for Scheme
7 | - is written in, and can be called from ABAP
8 |
9 | ## Getting Started
10 | The code can be cloned with [ABAP GIT](http://docs.abapgit.org/).
11 |
12 | - The main version is developed on Netweaver 7.5 and should work on ABAP Netweaver 7.4.
13 | - Milestones are downported to other branches (7.02).
14 | - The legacy code on [SCN Code Gallery](https://wiki.scn.sap.com/wiki/display/Snippets/Lisp+Interpreter+in+ABAP) should work on older releases.
15 |
16 | To check your installation, execute this guess my number game...
17 |
18 | ```Scheme
19 | (begin (display "Please enter a number between 1 - 100: ")
20 | (do ((quit #f)
21 | (guess 0)
22 | (answer (+ 1 (random 100))) )
23 | (quit)
24 | (begin (set! guess (read)) (display guess) )
25 | (cond ((and (number? guess) (< guess answer)) (display "\nToo low. Please guess again: ") )
26 | ((and (number? guess) (> guess answer)) (display "\nToo high. Please guess again: ") )
27 | (else (set! quit #t) (if (number? guess) (display "\nCorrect!")
28 | (display "\nGood bye...") ) ) ) ) )
29 | ```
30 |
31 | Scheme syntax is based upon nested parenthesization. The [wiki pages](https://github.com/nomssi/abap_scheme/wiki) are a good place to start.
32 |
33 | * I suggest you check the [syntax](https://github.com/nomssi/abap_scheme/wiki/Learn-Try-Scheme) and understand [Lists](https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Lists.html#Lists).
34 | * For questions/comments/bugs/feature requests/wishes please create an [issue](https://github.com/nomssi/abap_scheme/issues)
35 | * How to [enable the new editor](/editor)
36 |
37 | ## Why Scheme?
38 | - [Scheme](https://en.wikipedia.org/wiki/Scheme_%28programming_language%29) is one of the main Lisp dialects, alongside *Common Lisp* and *Clojure*. Conrad Barski's [Land of Lisp](http://landoflisp.com), Martin Ceronio's [LISP interpreter in ABAP](https://blogs.sap.com/2015/06/24/a-lisp-interpreter-in-abap/) and [Peter Norvig](http://norvig.com/lispy2.html) inspired me to learn Lisp. It is common to [Make your own Lisp](https://github.com/kanaka/mal/blob/master/process/guide.md) to really understand Lisp's core concepts.
39 |
40 | [](http://lisperati.com/logo.html)
41 |
42 | - Scheme's uses *symbolic expressions* (S-exps) to represent code *and* data. Expressions are then [evaluated](https://docs.racket-lang.org/reference/eval-model.html). Those concepts cannot be expressed in ABAP, except by first implementing a Lisp interpreter in ABAP ([Greenspun 10th rule](http://www.paulgraham.com/quotes.html) ).
43 |
44 | - My initial plan was to write a Lisp workbench for [Martin's Lisp interpreter](https://github.com/mydoghasworms/abap-lisp). I changed the target language after reading the *Revised 7 Report on the Algorithmic Language Scheme* aka [R7RS small](http://www.r7rs.org/) that offers a lot of examples to verify the interpreter. With this I can aim at compatibility with open source Scheme code.
45 |
46 | - In constrast to ABAP, Scheme has a very small number of rules for forming expressions that can be composed without restrictions. Scheme is lexically scoped and requires proper tail call optimization. Scheme is apt at [symbolic processing](https://github.com/nomssi/abap_scheme/wiki/Learn-Try-Symbolic-Derivation).
47 |
48 | ### Features
49 | - ABAP Scheme supports a subset of [R7RS](http://www.r7rs.org/) with some [Racket](https://docs.racket-lang.org/) extensions. Check the current [list of features](https://github.com/nomssi/abap_scheme/wiki/Features)
50 | - This documentation is the source of many of the 500+ tests implemented in the ABAP unit test suite.
51 | - Access to ABAP global fields and function modules
52 | - a programming environment to make it fun to use, featuring the editor and console views, a trace view, a graphical S-Expression viewer
53 |
54 | S-expression for (* 2 (+ 3 4)) | workbench view
55 | --- | ---
56 |  | 
57 |
58 | - R7RS alignment makes it easier to run open source Scheme code. This is however limited, as *first class continuations* (call cc) and *hygienic macros* (define-syntax) are missing
59 |
60 | ### Architecture
61 |
62 | - Report ZZ_LISP_IDE - Main report for the workbench
63 | - Include YY_LIB_LISP - Complete ABAP LISP library
64 | - Include YY_LISP_AUNIT - a large _ABAP Unit_ regression test suite
65 | - Include YY_LISP_IDE - Editor/Tools
66 |
67 | ### ABAP Integration
68 | #### Interpreter
69 | Class `lcl_lisp_interpreter` evaluates your Scheme code in a string `code`, using either method `eval_repl( code )` which throws an exception on errors, or method `eval_source( code )` catches exception:
70 |
71 | ```ABAP
72 | DATA(response) = NEW lcl_lisp_interpreter( io_port = port
73 | ii_log = log )->eval_source( code ).
74 | ```
75 | `port` is a buffered port that can allow input or output. `log` implements a simple logging interface with 2 methods, put( ) and get( ).
76 | #### Access to ABAP Fields
77 | For a [dynamic IF statement](https://blogs.sap.com/2016/02/29/dynamic-if-condition/)
78 | `( PLAAB = '02' ) and ( DELKZ = 'BB') and ( LIFNR > '' ) and ( PLUMI = '-')`
79 | we concatenate the following Scheme expression in a string variable `code` and evaluate.
80 |
81 | ```Scheme
82 | (let
83 | ; Define local fields
84 | ((PLAAB (ab-data "GS_MDPS-PLAAB" ))
85 | (DELKZ (ab-data "GS_MDPS-DELKZ" ))
86 | (LIFNR (ab-data "GS_MDPS-LIFNR" ))
87 | (PLUMI (ab-data "GS_MDPS-PLUMI" )))
88 | (and (= PLAAB '02') (= DELKZ 'BB') (> LIFNR '') (= PLUMI '-')) )
89 | ```
90 |
91 | The result on the expression either `#t` or `#f`.
92 |
93 | #### Function Module Call
94 |
95 | ```Scheme
96 | (let (( profiles
97 | (let ( (f3 (ab-function "BAPI_USER_GET_DETAIL")) )
98 | ( begin (ab-set f3 "USERNAME" (ab-get ab-sy "UNAME") ) ; param USERNAME = sy-uname
99 | (f3) ; function module call
100 | (ab-get f3 "PROFILES") ) ) ; return table PROFILES
101 | ) )
102 | (let ((profile (ab-get profiles 1)) ) ; read table PROFILES index 1 INTO profile
103 | (ab-get profile "BAPIPROF" ) ) ) ; read field profile-bapiprof
104 | ```
105 |
106 | #### Optional: Console Interface
107 |
108 | ```ABAP
109 | INTERFACE lif_input_port.
110 | METHODS read IMPORTING iv_title TYPE string OPTIONAL
111 | RETURNING VALUE(rv_input) TYPE string.
112 | METHODS peek_char RETURNING VALUE(rv_char) TYPE char01.
113 | METHODS is_char_ready RETURNING VALUE(rv_flag) TYPE flag.
114 | METHODS read_char RETURNING VALUE(rv_char) TYPE char01.
115 | METHODS put IMPORTING iv_text TYPE string.
116 | ENDINTERFACE.
117 |
118 | INTERFACE lif_output_port.
119 | METHODS write IMPORTING element TYPE REF TO lcl_lisp.
120 | METHODS display IMPORTING element TYPE REF TO lcl_lisp
121 | RAISING lcx_lisp_exception.
122 | ENDINTERFACE.
123 | ```
124 |
125 | ### Workbench
126 | 
127 | 
128 | 
129 |
130 |
131 | Read the ABAP Scheme [announcement](https://blogs.sap.com/2018/02/01/announcing-the-abap-scheme-workbench/) blog
132 |
--------------------------------------------------------------------------------
/editor/lisp_spec.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Jacques Nomssi
6 | LangSpec
7 | LISP
8 | Language specification for Scheme
9 |
10 |
11 | *.scm
12 | 1
13 | ()[]''""||{}
14 |
15 | (),
16 |
17 | 0-9a-Z_/<>!$%&*+-.:=?@^~
18 |
19 |
20 |
21 |
22 |
23 |
24 | 2
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | ;
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
--------------------------------------------------------------------------------
/src/zz_lisp_ide.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZZ_LISP_IDE
7 | 1
8 | *
9 | K
10 | E
11 | X
12 | X
13 |
14 |
15 | -
16 |
17 | ZZ_LISP_IDE
18 | 0100
19 | E
20 | ABAP LISP Workbench
21 | N
22 | 0100
23 | 027
24 | 120
25 |
26 |
27 |
28 | SCREEN
29 | SCREEN
30 |
31 |
32 |
33 |
34 | SCREEN
35 | SCREEN
36 | OKCODE
37 | G_OK_CODE
38 | ____________________
39 | 020
40 | 020
41 | 001
42 | CHAR
43 | X
44 |
45 |
46 |
47 |
48 | PROCESS BEFORE OUTPUT.
49 |
50 |
51 | MODULE status_0100.
52 |
53 |
54 |
55 | PROCESS AFTER INPUT.
56 |
57 |
58 | MODULE cancel_0100 AT EXIT-COMMAND.
59 |
60 |
61 | MODULE user_command_0100.
62 |
63 |
64 |
65 |
66 |
67 |
68 | 000001
69 | 000005
70 | 000001
71 |
72 |
73 |
74 | STATUS_100
75 | D
76 | 000001
77 | 000001
78 | 0001
79 | ABAP LISP Status
80 |
81 |
82 |
83 |
84 | BACK
85 | 001
86 | E
87 | S
88 | Back
89 |
90 |
91 | CANCEL
92 | 001
93 | E
94 | S
95 | ICON_CANCEL
96 | @0W@
97 | Cancel
98 |
99 |
100 | CLEAR
101 | 001
102 | S
103 | ICON_DELETE
104 | @11@
105 | Refresh
106 | Refresh
107 | Delete Source
108 | E
109 |
110 |
111 | EXECUTE
112 | 001
113 | S
114 | ICON_SYSTEM_PLAY
115 | @I6@
116 | Evaluate
117 | Evaluate
118 | Run
119 | V
120 |
121 |
122 | EXIT
123 | 001
124 | E
125 | S
126 | Exit
127 | X
128 |
129 |
130 | GRAPH
131 | 001
132 | S
133 | ICON_TREE
134 | @3M@
135 | S-Expression
136 | S-Expression
137 | View nested list data
138 | I
139 |
140 |
141 | GRPHCFG
142 | 001
143 | S
144 | Graph Config...
145 | G
146 |
147 |
148 | HELP
149 | 001
150 | S
151 | ICON_INFORMATION
152 | @0S@
153 | Help
154 | Help
155 | Online manual
156 | H
157 |
158 |
159 | NEXT
160 | 001
161 | S
162 | ICON_ARROW_RIGHT
163 | @9T@
164 | Next
165 | Next
166 | Next expression
167 |
168 |
169 | PREV
170 | 001
171 | S
172 | ICON_ARROW_LEFT
173 | @9S@
174 | Previous
175 | Previous
176 | Previous expression
177 |
178 |
179 | TRACE
180 | 001
181 | S
182 | Eval with Trace
183 | A
184 |
185 |
186 | VALIDATE
187 | 001
188 | S
189 | Eval with Trace
190 |
191 |
192 | VALIDATE
193 | 002
194 | S
195 | Check Syntax
196 | Help on..
197 | C
198 |
199 |
200 | WIKI
201 | 001
202 | S
203 | ICON_INFORMATION
204 | @0S@
205 | Help
206 | Help on..
207 | Online manual
208 |
209 |
210 |
211 |
212 | 000001
213 | 01
214 | F
215 | EXECUTE
216 | 001
217 |
218 |
219 | 000001
220 | 02
221 | F
222 | TRACE
223 | 001
224 |
225 |
226 | 000001
227 | 03
228 | F
229 | VALIDATE
230 | 002
231 |
232 |
233 | 000001
234 | 04
235 | S
236 |
237 |
238 | 000001
239 | 05
240 | F
241 | GRAPH
242 | 001
243 |
244 |
245 | 000001
246 | 06
247 | F
248 | GRPHCFG
249 | 001
250 |
251 |
252 | 000001
253 | 07
254 | S
255 |
256 |
257 | 000001
258 | 08
259 | F
260 | CLEAR
261 | 001
262 |
263 |
264 | 000001
265 | 09
266 | F
267 | EXIT
268 | 001
269 |
270 |
271 |
272 |
273 | 000001
274 | S
275 | User Interface
276 | U
277 | Standard Supplement
278 |
279 |
280 |
281 |
282 | 000001
283 | 01
284 | 000001
285 |
286 |
287 |
288 |
289 | 000001
290 | 0001
291 | 01
292 | 08
293 |
294 |
295 | 000001
296 | 0001
297 | 02
298 | 02
299 |
300 |
301 | 000001
302 | 0001
303 | 03
304 | 23
305 |
306 |
307 | 000001
308 | 0001
309 | 04
310 | 24
311 |
312 |
313 | 000001
314 | 0001
315 | 05
316 | 14
317 |
318 |
319 | 000001
320 | 0001
321 | 06
322 | S
323 |
324 |
325 | 000001
326 | 0001
327 | 07
328 | 13
329 |
330 |
331 |
332 |
333 | 000001
334 | 01
335 | HELP
336 | 001
337 |
338 |
339 | 000001
340 | 02
341 | GRAPH
342 | 001
343 |
344 |
345 | 000001
346 | 03
347 | BACK
348 | 001
349 |
350 |
351 | 000001
352 | 08
353 | EXECUTE
354 | 001
355 |
356 |
357 | 000001
358 | 12
359 | CANCEL
360 | 001
361 |
362 |
363 | 000001
364 | 13
365 | WIKI
366 | 001
367 |
368 |
369 | 000001
370 | 14
371 | CLEAR
372 | 001
373 |
374 |
375 | 000001
376 | 15
377 | EXIT
378 | 001
379 |
380 |
381 | 000001
382 | 23
383 | PREV
384 | 001
385 |
386 |
387 | 000001
388 | 24
389 | NEXT
390 | 001
391 |
392 |
393 |
394 |
395 | STATUS_100
396 | BACK
397 |
398 |
399 | STATUS_100
400 | CANCEL
401 |
402 |
403 | STATUS_100
404 | CLEAR
405 |
406 |
407 | STATUS_100
408 | EXECUTE
409 |
410 |
411 | STATUS_100
412 | EXIT
413 |
414 |
415 | STATUS_100
416 | GRAPH
417 |
418 |
419 | STATUS_100
420 | GRPHCFG
421 |
422 |
423 | STATUS_100
424 | HELP
425 |
426 |
427 | STATUS_100
428 | NEXT
429 |
430 |
431 | STATUS_100
432 | PREV
433 |
434 |
435 | STATUS_100
436 | TEST
437 |
438 |
439 | STATUS_100
440 | TRACE
441 |
442 |
443 | STATUS_100
444 | VALIDATE
445 |
446 |
447 | STATUS_100
448 | WIKI
449 |
450 |
451 |
452 |
453 | A
454 | 000001
455 | D
456 | ABAP LISP Status
457 |
458 |
459 | B
460 | 000001
461 | 0001
462 | D
463 | ABAP LISP Status
464 |
465 |
466 | P
467 | 000001
468 | D
469 | ABAP LISP Status
470 |
471 |
472 |
473 |
474 | TITLE_100
475 | ABAP LISP Workbench - &
476 |
477 |
478 |
479 |
480 | -
481 | I
482 | C00
483 | Remember my settings
484 | 40
485 |
486 | -
487 | I
488 | C10
489 | PlantUML Execution Mode
490 | 40
491 |
492 | -
493 | I
494 | C11
495 | PlantUML web service
496 | 40
497 |
498 | -
499 | I
500 | C12
501 | Save text file
502 | 24
503 |
504 | -
505 | I
506 | C13
507 | Local PlantUML
508 | 24
509 |
510 | -
511 | I
512 | C20
513 | PlantUML Settings
514 | 24
515 |
516 | -
517 | I
518 | C21
519 | Scale
520 | 15
521 |
522 | -
523 | I
524 | C25
525 | PlantUML Server
526 | 24
527 |
528 | -
529 | I
530 | C26
531 | Local PlantUML path
532 | 24
533 |
534 | -
535 | I
536 | C27
537 | Local PlantUML jar file
538 | 40
539 |
540 | -
541 | I
542 | C28
543 | Local Java path
544 | 24
545 |
546 | -
547 | I
548 | C32
549 | Display source
550 | 24
551 |
552 | -
553 | R
554 | Program ZZ_LISP_IDE
555 | 19
556 |
557 |
558 |
559 |
560 |
561 |
--------------------------------------------------------------------------------
/src/zcl_lisp_area.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_LISP_AREA
7 | E
8 | ABAP Lisp Workbench - Shared Area
9 | 45
10 | 1
11 | X
12 | X
13 | X
14 | S
15 |
16 |
17 |
18 | AREA_NAME
19 | E
20 | Name of an Area Class
21 |
22 |
23 | ATTACH_FOR_READ
24 | E
25 | Request a Read Lock
26 |
27 |
28 | ATTACH_FOR_UPDATE
29 | E
30 | Request a Change Lock
31 |
32 |
33 | ATTACH_FOR_WRITE
34 | E
35 | Request a Write Lock
36 |
37 |
38 | BUILD
39 | E
40 | Direct Call of Area Constructor
41 |
42 |
43 | CLASS_CONSTRUCTOR
44 | E
45 | CLASS_CONSTRUCTOR
46 |
47 |
48 | DETACH_AREA
49 | E
50 | Release all locks on all instances
51 |
52 |
53 | FREE_AREA
54 | E
55 | Delete all instances
56 |
57 |
58 | FREE_INSTANCE
59 | E
60 | Deletion of an Instance
61 |
62 |
63 | GET_GENERATOR_VERSION
64 | E
65 | Query Generator Version
66 |
67 |
68 | GET_INSTANCE_INFOS
69 | E
70 | Returns the names of all instances
71 |
72 |
73 | INVALIDATE_AREA
74 | E
75 | Active versions of all instances will be set to obsolete
76 |
77 |
78 | INVALIDATE_INSTANCE
79 | E
80 | Active version of one instance will be set to obsolete
81 |
82 |
83 | ROOT
84 | E
85 | SHM: Model of a Data Class
86 |
87 |
88 | SET_ROOT
89 | E
90 | Sets Root Objects
91 |
92 |
93 | _LIFE_CONTEXT
94 | E
95 | Lifetime of an Area (Constants in CL_SHM_AREA)
96 |
97 |
98 | _TRACE_ACTIVE
99 | E
100 | (Internal) Flag: Trace Active?
101 |
102 |
103 | _TRACE_SERVICE
104 | E
105 | (Internal) Reference to Trace Class
106 |
107 |
108 | _VERSION_
109 | E
110 | (internal)
111 |
112 |
113 |
114 |
115 | ATTACH_FOR_READ
116 | CX_SHM_CHANGE_LOCK_ACTIVE
117 | E
118 | A Change Lock Is Already Active
119 |
120 |
121 | ATTACH_FOR_READ
122 | CX_SHM_EXCLUSIVE_LOCK_ACTIVE
123 | E
124 | Instance Already Locked
125 |
126 |
127 | ATTACH_FOR_READ
128 | CX_SHM_INCONSISTENT
129 | E
130 | Different Definitions Between Program and Area
131 |
132 |
133 | ATTACH_FOR_READ
134 | CX_SHM_NO_ACTIVE_VERSION
135 | E
136 | No active version exists for an attach
137 |
138 |
139 | ATTACH_FOR_READ
140 | CX_SHM_PARAMETER_ERROR
141 | E
142 | Incorrect parameter passed
143 |
144 |
145 | ATTACH_FOR_READ
146 | CX_SHM_READ_LOCK_ACTIVE
147 | E
148 | Request for a Second Read Lock
149 |
150 |
151 | ATTACH_FOR_READ
152 | HANDLE
153 | E
154 | SHM: Model of an Area Class
155 |
156 |
157 | ATTACH_FOR_READ
158 | INST_NAME
159 | E
160 | Name of a Shared Object Instance of an Area
161 |
162 |
163 | ATTACH_FOR_UPDATE
164 | ATTACH_MODE
165 | E
166 | Mode of ATTACH (Constants in CL_SHM_AREA)
167 |
168 |
169 | ATTACH_FOR_UPDATE
170 | CX_SHM_CHANGE_LOCK_ACTIVE
171 | E
172 | A write lock is already active
173 |
174 |
175 | ATTACH_FOR_UPDATE
176 | CX_SHM_EXCLUSIVE_LOCK_ACTIVE
177 | E
178 | Instance Already Locked
179 |
180 |
181 | ATTACH_FOR_UPDATE
182 | CX_SHM_INCONSISTENT
183 | E
184 | Different Definitions Between Program and Area
185 |
186 |
187 | ATTACH_FOR_UPDATE
188 | CX_SHM_NO_ACTIVE_VERSION
189 | E
190 | No active version exists for an attach
191 |
192 |
193 | ATTACH_FOR_UPDATE
194 | CX_SHM_PARAMETER_ERROR
195 | E
196 | Passed parameter has incorrect value
197 |
198 |
199 | ATTACH_FOR_UPDATE
200 | CX_SHM_PENDING_LOCK_REMOVED
201 | E
202 | Shared Objects: Waiting Lock Was Deleted
203 |
204 |
205 | ATTACH_FOR_UPDATE
206 | CX_SHM_VERSION_LIMIT_EXCEEDED
207 | E
208 | No Additional Versions Available
209 |
210 |
211 | ATTACH_FOR_UPDATE
212 | HANDLE
213 | E
214 | SHM: Model of an Area Class
215 |
216 |
217 | ATTACH_FOR_UPDATE
218 | INST_NAME
219 | E
220 | Name of a Shared Object Instance of an Area
221 |
222 |
223 | ATTACH_FOR_UPDATE
224 | WAIT_TIME
225 | E
226 | Maximum Wait Time (in Milliseconds)
227 |
228 |
229 | ATTACH_FOR_WRITE
230 | ATTACH_MODE
231 | E
232 | Mode of ATTACH (Constants in CL_SHM_AREA)
233 |
234 |
235 | ATTACH_FOR_WRITE
236 | CX_SHM_CHANGE_LOCK_ACTIVE
237 | E
238 | A write lock is already active
239 |
240 |
241 | ATTACH_FOR_WRITE
242 | CX_SHM_EXCLUSIVE_LOCK_ACTIVE
243 | E
244 | Instance Already Locked
245 |
246 |
247 | ATTACH_FOR_WRITE
248 | CX_SHM_PARAMETER_ERROR
249 | E
250 | Passed parameter has incorrect value
251 |
252 |
253 | ATTACH_FOR_WRITE
254 | CX_SHM_PENDING_LOCK_REMOVED
255 | E
256 | Shared Objects: Waiting Lock Was Deleted
257 |
258 |
259 | ATTACH_FOR_WRITE
260 | CX_SHM_VERSION_LIMIT_EXCEEDED
261 | E
262 | No Additional Versions Available
263 |
264 |
265 | ATTACH_FOR_WRITE
266 | HANDLE
267 | E
268 | SHM: Model of an Area Class
269 |
270 |
271 | ATTACH_FOR_WRITE
272 | INST_NAME
273 | E
274 | Name of a Shared Object Instance of an Area
275 |
276 |
277 | ATTACH_FOR_WRITE
278 | WAIT_TIME
279 | E
280 | Maximum Wait Time (in Milliseconds)
281 |
282 |
283 | BUILD
284 | CX_SHMA_INCONSISTENT
285 | E
286 | SHM Administration: Inconsistent Attribute Combination
287 |
288 |
289 | BUILD
290 | CX_SHMA_NOT_CONFIGURED
291 | E
292 | SHM Administration: Area Property Is Not Configured
293 |
294 |
295 | BUILD
296 | CX_SHM_BUILD_FAILED
297 | E
298 | Constructor Run Failed
299 |
300 |
301 | BUILD
302 | INST_NAME
303 | E
304 | Name of a Shared Object Instance of an Area
305 |
306 |
307 | DETACH_AREA
308 | RC
309 | E
310 | Detach Return Value (Constants in CL_SHM_AREA)
311 |
312 |
313 | FREE_AREA
314 | AFFECT_SERVER
315 | E
316 | Servers on which the area is deleted or invalidated
317 |
318 |
319 | FREE_AREA
320 | CX_SHM_PARAMETER_ERROR
321 | E
322 | Incorrect parameter passed
323 |
324 |
325 | FREE_AREA
326 | RC
327 | E
328 | Return Value (Constants in CL_SHM_AREA)
329 |
330 |
331 | FREE_AREA
332 | TERMINATE_CHANGER
333 | E
334 | Writing processes will be ended
335 |
336 |
337 | FREE_INSTANCE
338 | AFFECT_SERVER
339 | E
340 | Servers on which the area is deleted or invalidated
341 |
342 |
343 | FREE_INSTANCE
344 | CX_SHM_PARAMETER_ERROR
345 | E
346 | Incorrect parameter passed
347 |
348 |
349 | FREE_INSTANCE
350 | INST_NAME
351 | E
352 | Name of a Shared Object Instance of an Area
353 |
354 |
355 | FREE_INSTANCE
356 | RC
357 | E
358 | Return Value (Constants in CL_SHM_AREA)
359 |
360 |
361 | FREE_INSTANCE
362 | TERMINATE_CHANGER
363 | E
364 | Writing processes will be ended
365 |
366 |
367 | GET_INSTANCE_INFOS
368 | INFOS
369 | E
370 | Overview of all Instances of an SHM Area
371 |
372 |
373 | GET_INSTANCE_INFOS
374 | INST_NAME
375 | E
376 | Name of a Shared Object Instance in an Area
377 |
378 |
379 | INVALIDATE_AREA
380 | AFFECT_SERVER
381 | E
382 | Servers on which the area is deleted or invalidated
383 |
384 |
385 | INVALIDATE_AREA
386 | CX_SHM_PARAMETER_ERROR
387 | E
388 | Incorrect parameter passed
389 |
390 |
391 | INVALIDATE_AREA
392 | RC
393 | E
394 | Detach Return Value (Constants in CL_SHM_AREA)
395 |
396 |
397 | INVALIDATE_AREA
398 | TERMINATE_CHANGER
399 | E
400 | Active writing processes will be ended
401 |
402 |
403 | INVALIDATE_INSTANCE
404 | AFFECT_SERVER
405 | E
406 | Servers on which the area is deleted or invalidated
407 |
408 |
409 | INVALIDATE_INSTANCE
410 | CX_SHM_PARAMETER_ERROR
411 | E
412 | Incorrect parameter passed
413 |
414 |
415 | INVALIDATE_INSTANCE
416 | INST_NAME
417 | E
418 | Name of a Shared Object Instance of an Area
419 |
420 |
421 | INVALIDATE_INSTANCE
422 | RC
423 | E
424 | Detach Return Value (Constants in CL_SHM_AREA)
425 |
426 |
427 | INVALIDATE_INSTANCE
428 | TERMINATE_CHANGER
429 | E
430 | Active writing processes will be ended
431 |
432 |
433 | SET_ROOT
434 | CX_SHM_INITIAL_REFERENCE
435 | E
436 | Initial reference passed
437 |
438 |
439 | SET_ROOT
440 | CX_SHM_WRONG_HANDLE
441 | E
442 | Incorrect Handle
443 |
444 |
445 | SET_ROOT
446 | ROOT
447 | E
448 | Root object
449 |
450 |
451 |
452 |
453 |
454 |
--------------------------------------------------------------------------------
/src/yy_lib_registry.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Include YY_LIB_REGISTRY
3 | *&---------------------------------------------------------------------*
4 | *& Was: Include ZLIBREGISTRY
5 | * Implementation of a registry for storing arbitrary values (similar to the MS Windows registry)
6 | * Author: Martin Ceronio (2015), http://ceronio.net
7 | * Released under MIT License: http://opensource.org/licenses/MIT
8 |
9 | CLASS lcx_registry_err DEFINITION INHERITING FROM cx_dynamic_check.
10 | ENDCLASS. "lcx_registry_err DEFINITION
11 |
12 | *----------------------------------------------------------------------*
13 | * CLASS lcx_registry_lock DEFINITION
14 | *----------------------------------------------------------------------*
15 | CLASS lcx_registry_lock DEFINITION INHERITING FROM lcx_registry_err.
16 | ENDCLASS. "lcx_registry_lock DEFINITION
17 |
18 | *----------------------------------------------------------------------*
19 | * CLASS lcx_registry_noentry DEFINITION
20 | *----------------------------------------------------------------------*
21 | CLASS lcx_registry_noentry DEFINITION INHERITING FROM lcx_registry_err.
22 | ENDCLASS. "lcx_registry_noentry DEFINITION
23 |
24 | *----------------------------------------------------------------------*
25 | * CLASS lcx_registry_entry_exists DEFINITION
26 | *----------------------------------------------------------------------*
27 | CLASS lcx_registry_entry_exists DEFINITION INHERITING FROM lcx_registry_err.
28 | ENDCLASS. "lcx_registry_entry_exists DEFINITION
29 |
30 | *----------------------------------------------------------------------*
31 | * CLASS lcx_registry_entry_deleted DEFINITION
32 | *----------------------------------------------------------------------*
33 | CLASS lcx_registry_entry_deleted DEFINITION INHERITING FROM lcx_registry_err.
34 | ENDCLASS. "lcx_registry_entry_deleted DEFINITION
35 |
36 | *----------------------------------------------------------------------*
37 | * CLASS lcx_registry_invalid_char DEFINITION
38 | *----------------------------------------------------------------------*
39 | CLASS lcx_registry_invalid_char DEFINITION INHERITING FROM lcx_registry_err.
40 | ENDCLASS. "lcx_registry_invalid_char DEFINITION
41 |
42 | CLASS lcl_registry_lock DEFINITION.
43 | PUBLIC SECTION.
44 | METHODS:
45 | constructor
46 | IMPORTING key TYPE indx_srtfd,
47 | set_optimistic
48 | RAISING lcx_registry_lock,
49 | promote
50 | RAISING lcx_registry_lock,
51 | release.
52 |
53 | METHODS
54 | get_uuid RETURNING VALUE(rv_uuid) TYPE sysuuid_c22
55 | RAISING lcx_registry_err.
56 | PRIVATE SECTION.
57 | DATA internal_key TYPE indx_srtfd.
58 | ENDCLASS.
59 | *----------------------------------------------------------------------*
60 | * CLASS lcl_registry_entry DEFINITION
61 | *----------------------------------------------------------------------*
62 | *
63 | *----------------------------------------------------------------------*
64 | CLASS lcl_registry_entry DEFINITION CREATE PROTECTED.
65 |
66 | PUBLIC SECTION.
67 | * Predefined key for the registry root:
68 | CLASS-DATA registry_root TYPE indx_srtfd READ-ONLY VALUE 'REGISTRY_ROOT'.
69 |
70 | TYPES: BEGIN OF ts_keyval,
71 | key TYPE string,
72 | value TYPE string,
73 | END OF ts_keyval.
74 | TYPES: tt_keyval TYPE SORTED TABLE OF ts_keyval WITH UNIQUE KEY key.
75 |
76 | * For keeping track of references to sub-entries, we maintain a shadow
77 | * table with the same keys
78 | TYPES: BEGIN OF ts_keyobj,
79 | key TYPE string,
80 | value TYPE REF TO lcl_registry_entry,
81 | END OF ts_keyobj.
82 | TYPES: tt_keyobj TYPE SORTED TABLE OF ts_keyobj WITH UNIQUE KEY key.
83 |
84 | DATA sub_entries TYPE tt_keyval READ-ONLY.
85 | DATA values TYPE tt_keyval READ-ONLY.
86 | DATA internal_key TYPE indx_srtfd READ-ONLY.
87 | DATA parent_key TYPE indx_srtfd READ-ONLY.
88 | DATA entry_id TYPE string READ-ONLY. "User-friendly ID of the subnode
89 |
90 | METHODS:
91 | constructor
92 | IMPORTING internal_key TYPE any,
93 | reload
94 | RAISING lcx_registry_noentry,
95 | * lock raising lcx_registry_err,
96 | * Saves entry and all dirty sub-entries
97 | save RAISING lcx_registry_err,
98 |
99 | get_parent
100 | RETURNING VALUE(parent) TYPE REF TO lcl_registry_entry,
101 |
102 | create_by_path
103 | IMPORTING path TYPE string
104 | RETURNING VALUE(entry) TYPE REF TO lcl_registry_entry
105 | RAISING lcx_registry_err,
106 |
107 | *--------------------------------------------------------------------*
108 | * Methods dealing with sub-entries of the registry entry
109 | get_subentry
110 | IMPORTING key TYPE clike
111 | RETURNING VALUE(entry) TYPE REF TO lcl_registry_entry,
112 | add_subentry
113 | IMPORTING key TYPE clike
114 | RETURNING VALUE(entry) TYPE REF TO lcl_registry_entry
115 | RAISING lcx_registry_entry_exists,
116 | * Removes sub-entry and all entries underneath
117 | remove_subentry
118 | IMPORTING key TYPE clike
119 | RAISING lcx_registry_err,
120 | remove_subentries
121 | RAISING lcx_registry_err,
122 | copy_subentry
123 | IMPORTING source_key TYPE clike
124 | target_key TYPE clike
125 | RETURNING VALUE(target_entry) TYPE REF TO lcl_registry_entry
126 | RAISING lcx_registry_err,
127 |
128 | get_subentry_keys
129 | RETURNING VALUE(keys) TYPE string_table,
130 |
131 | get_subentries
132 | RETURNING VALUE(sub_entries) TYPE tt_keyobj,
133 |
134 | * Methods for dealing with values in the registry entry:
135 |
136 | * Get keys of all values
137 | get_value_keys
138 | RETURNING VALUE(keys) TYPE string_table,
139 | * Get all values
140 | get_values
141 | RETURNING VALUE(values) TYPE tt_keyval,
142 | * Set all values in one go:
143 | set_values
144 | IMPORTING values TYPE tt_keyval,
145 | * Get single value by key
146 | get_value
147 | IMPORTING key TYPE clike
148 | RETURNING VALUE(value) TYPE string
149 | RAISING lcx_registry_noentry,
150 | * Set/overwrite single value
151 | set_value
152 | IMPORTING key TYPE clike
153 | value TYPE any,
154 | * Delete single value by key
155 | delete_value
156 | IMPORTING key TYPE clike.
157 |
158 |
159 | CLASS-METHODS:
160 | get_entry_by_internal_key
161 | IMPORTING key TYPE any
162 | RETURNING VALUE(entry) TYPE REF TO lcl_registry_entry,
163 | get_root
164 | RETURNING VALUE(root) TYPE REF TO lcl_registry_entry.
165 |
166 | PROTECTED SECTION.
167 |
168 | METHODS:
169 | copy_subentry_deep
170 | IMPORTING source TYPE REF TO lcl_registry_entry
171 | target TYPE REF TO lcl_registry_entry,
172 | * Remove the registry entry from the database:
173 | * The DELETE method is protected because you must always delete an entry
174 | * as the sub-entry of its parent so that the link is removed from the
175 | * parent
176 | delete
177 | RAISING lcx_registry_err.
178 |
179 | DATA deleted TYPE abap_bool.
180 |
181 | CLASS-DATA lock TYPE REF TO lcl_registry_lock.
182 |
183 | * Class-wide buffer of instances of registry entries
184 | CLASS-DATA registry_entries TYPE tt_keyobj.
185 |
186 |
187 | ENDCLASS. "lcl_registry_entry DEFINITION
188 |
189 | *----------------------------------------------------------------------*
190 | * CLASS lcl_registry_entry IMPLEMENTATION
191 | *----------------------------------------------------------------------*
192 | *
193 | *----------------------------------------------------------------------*
194 | CLASS lcl_registry_entry IMPLEMENTATION.
195 |
196 | *--------------------------------------------------------------------*
197 | * CONSTRUCTOR - new instance of registry key
198 | *--------------------------------------------------------------------*
199 | METHOD constructor.
200 | me->internal_key = internal_key.
201 |
202 | lock = NEW lcl_registry_lock( me->internal_key ).
203 |
204 | * Load the entry from the database
205 | reload( ).
206 |
207 | * Object inserts itself into registry of entries
208 | INSERT VALUE ts_keyobj( key = me->internal_key
209 | value = me ) INTO TABLE registry_entries.
210 | ENDMETHOD. "constructor
211 |
212 | *--------------------------------------------------------------------*
213 | * RELOAD - reload values and sub-entries from database, set new lock
214 | *--------------------------------------------------------------------*
215 | METHOD reload.
216 | * Reload the values and sub-entries from the database
217 | IMPORT values = me->values
218 | sub_entries = me->sub_entries
219 | parent = parent_key
220 | entry_id = entry_id FROM DATABASE indx(zr) ID internal_key.
221 | IF sy-subrc NE 0.
222 | RAISE EXCEPTION TYPE lcx_registry_noentry.
223 | ENDIF.
224 |
225 | lock->set_optimistic( ).
226 | ENDMETHOD. "reload
227 |
228 | *--------------------------------------------------------------------*
229 | * GET_ROOT - retrieve root entry of registry
230 | *--------------------------------------------------------------------*
231 | METHOD get_root.
232 | * If the root doesn't exist yet, create it
233 | DATA values TYPE tt_keyval.
234 | DATA sub_entries TYPE tt_keyval.
235 | DATA parent_key TYPE indx_srtfd VALUE space.
236 | DATA entry_id TYPE string.
237 |
238 | IMPORT values = values
239 | sub_entries = sub_entries FROM DATABASE indx(zr) ID registry_root.
240 | IF sy-subrc NE 0.
241 | entry_id = registry_root.
242 | EXPORT values = values
243 | sub_entries = sub_entries
244 | parent = parent_key
245 | entry_id = entry_id TO DATABASE indx(zr) ID registry_root.
246 | ENDIF.
247 |
248 | * Retrieve the root entry of the registry
249 | root = get_entry_by_internal_key( registry_root ).
250 |
251 | ENDMETHOD. "get_root
252 |
253 | *--------------------------------------------------------------------*
254 | * GET_ENTRY_BY_INTERNAL_KEY - retrieve reg. entry by internal ID
255 | *--------------------------------------------------------------------*
256 | METHOD get_entry_by_internal_key.
257 | * Search global index of registry entry instances
258 |
259 | entry = VALUE #( registry_entries[ key = key ]-value DEFAULT
260 | NEW #( internal_key = key ) ). " will insert itself in registry
261 |
262 | ENDMETHOD. "get_entry_by_internal_key
263 |
264 | *--------------------------------------------------------------------*
265 | * CREATE_BY_PATH - convenience method, analogous to mkdir -p that
266 | * allows you to create a path of registry entries if they do not yet
267 | * exist; paths must be separated by forward slash ('/')
268 | * Sub-entries are created from the current registry entry
269 | *--------------------------------------------------------------------*
270 | METHOD create_by_path.
271 | DATA sub_entry TYPE REF TO lcl_registry_entry.
272 |
273 | SPLIT path AT '/' INTO TABLE DATA(keys).
274 |
275 | entry = me.
276 | LOOP AT keys INTO DATA(key) WHERE table_line IS NOT INITIAL.
277 | sub_entry = entry->get_subentry( key ).
278 | IF sub_entry IS NOT BOUND.
279 | sub_entry = entry->add_subentry( key ).
280 | ENDIF.
281 | entry = sub_entry.
282 | ENDLOOP.
283 | * After successful processing of chain, ENTRY will contain the last-created node
284 |
285 | ENDMETHOD. "create_by_path
286 |
287 | *--------------------------------------------------------------------*
288 | * GET_PARENT - retrieve parent entry of this entry
289 | *--------------------------------------------------------------------*
290 | METHOD get_parent.
291 | * Return the parent of the current key
292 | parent = get_entry_by_internal_key( parent_key ).
293 | ENDMETHOD. "get_parent
294 |
295 | *--------------------------------------------------------------------*
296 | * GET_SUBENTRY - return single child entry by key
297 | *--------------------------------------------------------------------*
298 | METHOD get_subentry.
299 |
300 | CLEAR entry.
301 | * Read internal store of sub-entries
302 | CHECK line_exists( sub_entries[ key = key ] ).
303 |
304 | DATA(lv_value) = sub_entries[ key = key ]-value.
305 |
306 | * Search global index of registry entry instances
307 | * read table sub_entrobj into ko with key key = kv-value.
308 |
309 | entry = VALUE #( registry_entries[ key = lv_value ]-value
310 | DEFAULT NEW #( internal_key = lv_value ) ).
311 | * Create new reference to sub-entry, Will insert itself into registry entries
312 |
313 | ENDMETHOD. "get_subentry
314 |
315 | *--------------------------------------------------------------------*
316 | * GET_SUBENTRIES - return immediate children registry entries
317 | *--------------------------------------------------------------------*
318 | METHOD get_subentries.
319 | LOOP AT get_subentry_keys( ) INTO DATA(subkey).
320 | INSERT VALUE #( key = subkey
321 | value = get_subentry( subkey ) ) INTO TABLE sub_entries.
322 | ENDLOOP.
323 | ENDMETHOD. "get_subentries
324 |
325 | DEFINE validate.
326 | * Prevent any changes if this entry is marked as deleted
327 | IF deleted = abap_true.
328 | RAISE EXCEPTION TYPE lcx_registry_entry_deleted.
329 | ENDIF.
330 | END-OF-DEFINITION.
331 |
332 | *--------------------------------------------------------------------*
333 | * ADD_SUBENTRY - add a child entry with new key and save
334 | *--------------------------------------------------------------------*
335 | METHOD add_subentry.
336 | validate.
337 |
338 | * Check that only allowed characters are used. Will help for making
339 | * sensible paths and string handling in other applications
340 | * Most of all, we want to avoid spaces and slashes (although those
341 | * square and curly brackets could cause problems for JSON...)
342 | IF NOT key CO 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890@#$%^_+-(){}[]'.
343 | RAISE EXCEPTION TYPE lcx_registry_invalid_char.
344 | ENDIF.
345 |
346 | * Read internal store of sub-entries
347 | IF line_exists( sub_entries[ key = key ] ).
348 | RAISE EXCEPTION TYPE lcx_registry_entry_exists.
349 | ENDIF.
350 |
351 | DATA(lv_value) = lock->get_uuid( ).
352 | INSERT VALUE #( key = key
353 | value = lv_value ) INTO TABLE sub_entries.
354 |
355 | * Create an entry on the database for the new entry
356 | DATA lt_empty_vals TYPE tt_keyval.
357 | DATA lv_srtfd TYPE indx_srtfd.
358 | lv_srtfd = lv_value.
359 |
360 | EXPORT values = lt_empty_vals
361 | sub_entries = lt_empty_vals
362 | parent = internal_key
363 | entry_id = key TO DATABASE indx(zr) ID lv_srtfd.
364 |
365 | entry = NEW #( internal_key = lv_value ).
366 | * Will insert itself into registry entries
367 |
368 | ** Set current entry as the parent of the new entry
369 | * entry->parent_key = internal_key.
370 | ** Set short ID on the new entry
371 | * entry->entry_id = key.
372 | ** Save the new entry
373 | * entry->save( ).
374 |
375 | * Save the current entry to update the list of sub-keys
376 | save( ).
377 |
378 | ENDMETHOD. "add_subentry
379 |
380 | *--------------------------------------------------------------------*
381 | * COPY_SUBENTRY - copy a child registry entry at the same level,
382 | * including all values, by passing a source and target key
383 | *--------------------------------------------------------------------*
384 | METHOD copy_subentry.
385 | validate.
386 |
387 | DATA(source_entry) = get_subentry( source_key ).
388 | IF source_entry IS NOT BOUND.
389 | RAISE EXCEPTION TYPE lcx_registry_noentry.
390 | ENDIF.
391 |
392 | * Using the source and the new target, do a deep copy
393 | * that includes copies of sub-entries and values
394 | copy_subentry_deep( source = source_entry
395 | target = add_subentry( target_key ) ).
396 |
397 | ENDMETHOD. "copy_subentry
398 |
399 | *--------------------------------------------------------------------*
400 | * COPY_SUBENTRY_DEEP - (protected) - copy a branch of the registry
401 | * at the same level, including all values
402 | *--------------------------------------------------------------------*
403 | METHOD copy_subentry_deep.
404 |
405 | * Copy values from source to target
406 | target->values = source->values.
407 |
408 | * Copy sub-entries from source to target
409 | LOOP AT source->sub_entries INTO DATA(ls_subentry).
410 | copy_subentry_deep( source = source->get_subentry( ls_subentry-key )
411 | target = target->add_subentry( ls_subentry-key ) ).
412 | ENDLOOP.
413 |
414 | * Ensure that values are also saved
415 | save( ).
416 |
417 | ENDMETHOD. "copy_subentry_deep
418 |
419 | *--------------------------------------------------------------------*
420 | * REMOVE_SUBENTRIES - remove all child entries of this entry
421 | *--------------------------------------------------------------------*
422 | METHOD remove_subentries.
423 | validate.
424 |
425 | LOOP AT sub_entries INTO DATA(kv).
426 | remove_subentry( kv-key ).
427 | ENDLOOP.
428 | ENDMETHOD. "remove_subentries
429 |
430 | *--------------------------------------------------------------------*
431 | * DELETE - delete the current entry from the database and mark it,
432 | * preventing any further operations on this entry
433 | *--------------------------------------------------------------------*
434 | METHOD delete.
435 | validate.
436 |
437 | * Delete all sub-entries before deleting this entry
438 | LOOP AT sub_entries INTO DATA(sub_entry).
439 | get_subentry( sub_entry-key )->delete( ).
440 | DELETE sub_entries.
441 | ENDLOOP.
442 |
443 | * Remove DB entry for the current entry
444 | lock->promote( ).
445 | DELETE FROM DATABASE indx(zr) ID internal_key.
446 | * Object removes itself from the global table too so that that reference no longer exists
447 | DELETE registry_entries WHERE key = internal_key.
448 | * Set the object to deleted to prevent any operations on any remaining references to the object
449 | deleted = abap_true.
450 |
451 | * Release lock held on this key
452 | lock->release( ).
453 |
454 | ENDMETHOD. "delete
455 |
456 | *--------------------------------------------------------------------*
457 | * REMOVE_SUBENTRY - remove a single child registry entry by key
458 | *--------------------------------------------------------------------*
459 | METHOD remove_subentry.
460 | validate.
461 |
462 | * Read internal store of sub-entries
463 | IF NOT line_exists( sub_entries[ key = key ] ).
464 | * Entry does not exist; exit with error
465 | RAISE EXCEPTION TYPE lcx_registry_noentry.
466 | ENDIF.
467 |
468 | * Remove all sub-entries of the sub-entry before removing the sub-entry
469 | DATA(sub_entry) = get_subentry( key ).
470 | CHECK sub_entry IS BOUND.
471 |
472 | * Delete the sub_entry (which deletes its sub-entries)
473 | sub_entry->delete( ).
474 | * Remove entry from sub-entry table and shadow table
475 | DELETE sub_entries WHERE key = key.
476 |
477 | save( ). "Save current entry to remove subentry that has been removed
478 |
479 | ENDMETHOD. "remove_subentry
480 |
481 | *--------------------------------------------------------------------*
482 | * SAVE - save the current entry, with concurrency control
483 | *--------------------------------------------------------------------*
484 | METHOD save.
485 | validate.
486 |
487 | lock->promote( ).
488 | EXPORT values = me->values
489 | sub_entries = me->sub_entries
490 | parent = parent_key
491 | entry_id = entry_id TO DATABASE indx(zr) ID internal_key.
492 | lock->set_optimistic( ).
493 | ENDMETHOD. "save
494 |
495 | *--------------------------------------------------------------------*
496 | * GET_SUBENTRY_KEYS - retrieve keys of all child registry entries
497 | *--------------------------------------------------------------------*
498 | METHOD get_subentry_keys.
499 | keys = VALUE #( FOR kv IN sub_entries ( kv-key ) ).
500 | ENDMETHOD. "get_subentry_keys
501 |
502 | *--------------------------------------------------------------------*
503 | * GET_VALUE_KEYS - retrieve keys of all values
504 | *--------------------------------------------------------------------*
505 | METHOD get_value_keys.
506 | keys = VALUE #( FOR kv IN values ( kv-key ) ).
507 | ENDMETHOD. "get_value_keys
508 |
509 | *--------------------------------------------------------------------*
510 | * GET_VALUES - retrieve all values at once in key+value table
511 | *--------------------------------------------------------------------*
512 | METHOD get_values.
513 | values = me->values.
514 | ENDMETHOD. "get_values
515 |
516 | *--------------------------------------------------------------------*
517 | * SET_VALUES - set all values at once with key+value table
518 | *--------------------------------------------------------------------*
519 | METHOD set_values.
520 | validate.
521 |
522 | me->values = values.
523 | ENDMETHOD. "set_values
524 |
525 | *--------------------------------------------------------------------*
526 | * GET_VALUE - return a single value by key
527 | *--------------------------------------------------------------------*
528 | METHOD get_value.
529 | TRY.
530 | value = values[ key = key ]-value.
531 | CATCH cx_sy_itab_line_not_found.
532 | RAISE EXCEPTION TYPE lcx_registry_noentry.
533 | ENDTRY.
534 | ENDMETHOD. "get_value
535 |
536 | METHOD set_value.
537 | validate.
538 |
539 | * Add the value to set of values if not existing or change if it does exist
540 | READ TABLE values INTO DATA(kv) WITH KEY key = key.
541 | IF sy-subrc NE 0.
542 | INSERT VALUE #( key = key
543 | value = value ) INTO TABLE values.
544 | ELSE.
545 | kv-value = value.
546 | MODIFY TABLE values FROM kv.
547 | ENDIF.
548 | ENDMETHOD. "set_value
549 |
550 | METHOD delete_value.
551 | validate.
552 |
553 | DELETE values WHERE key = key.
554 | ENDMETHOD. "delete_value
555 |
556 | ENDCLASS. "lcl_registry_entry IMPLEMENTATION
557 |
558 | CLASS lcl_registry_lock IMPLEMENTATION.
559 |
560 | **********************************************************************
561 | * CONCURRENCY HELPER METHODS
562 | **********************************************************************
563 | METHOD constructor.
564 | super->constructor( ).
565 | internal_key = key.
566 | ENDMETHOD.
567 |
568 | *--------------------------------------------------------------------*
569 | * SET_OPTIMISTIC_LOCK - always set when (re-)reading an entry
570 | *--------------------------------------------------------------------*
571 | METHOD set_optimistic.
572 | * Existing lock must be released before acquiring a new one
573 | release( ).
574 | CALL FUNCTION 'ENQUEUE_ESINDX'
575 | EXPORTING
576 | mode_indx = 'O'
577 | relid = 'ZR'
578 | srtfd = internal_key
579 | EXCEPTIONS
580 | foreign_lock = 1
581 | system_failure = 2
582 | OTHERS = 3.
583 | IF sy-subrc <> 0.
584 | RAISE EXCEPTION TYPE lcx_registry_lock.
585 | ENDIF.
586 | ENDMETHOD. "set_optimistic_lock
587 |
588 | *--------------------------------------------------------------------*
589 | * PROMOTE_LOCK - Get exclusive lock just before saving
590 | *--------------------------------------------------------------------*
591 | METHOD promote.
592 | CALL FUNCTION 'ENQUEUE_ESINDX'
593 | EXPORTING
594 | mode_indx = 'R'
595 | relid = 'ZR'
596 | srtfd = internal_key
597 | EXCEPTIONS
598 | foreign_lock = 1
599 | system_failure = 2
600 | OTHERS = 3.
601 | IF sy-subrc <> 0.
602 | RAISE EXCEPTION TYPE lcx_registry_lock.
603 | ENDIF.
604 | ENDMETHOD. "promote_lock
605 |
606 | *--------------------------------------------------------------------*
607 | * RELEASE_LOCK - called after deleting or before re-acquiring
608 | *--------------------------------------------------------------------*
609 | METHOD release.
610 | CALL FUNCTION 'DEQUEUE_ESINDX'
611 | EXPORTING
612 | relid = 'ZR'
613 | srtfd = internal_key.
614 | ENDMETHOD. "release_lock
615 |
616 | METHOD get_uuid.
617 | * Create unique ID for key in INDX for the new entry
618 | TRY.
619 | rv_uuid = cl_system_uuid=>create_uuid_c22_static( ).
620 | CATCH cx_uuid_error.
621 | RAISE EXCEPTION TYPE lcx_registry_err.
622 | ENDTRY.
623 | ENDMETHOD.
624 |
625 | ENDCLASS.
626 |
--------------------------------------------------------------------------------
/src/zz_registry_browser.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Report ZZ_REGISTRY_BROWSER
3 | *&---------------------------------------------------------------------*
4 | *& was Report ZUSR_REGISTRY_BROWSER
5 | *&---------------------------------------------------------------------*
6 | *& Viewer and editor for registry stored in INDX
7 | *& (requires ZLIB_REGISTRY)
8 | *&---------------------------------------------------------------------*
9 | * Author: Martin Ceronio (2015), http://ceronio.net
10 | * Released under MIT License: http://opensource.org/licenses/MIT
11 | REPORT zz_registry_browser.
12 |
13 | INCLUDE yy_lib_registry.
14 |
15 | * For tree control:
16 | DATA: gr_tree TYPE REF TO cl_gui_alv_tree.
17 | DATA: gr_tree_toolbar TYPE REF TO cl_gui_toolbar.
18 | DATA: gs_node_layout TYPE lvc_s_layn. "Layout for new nodes
19 | * Table for registry entries on tree
20 | TYPES: BEGIN OF ts_tab,
21 | key TYPE string,
22 | reg_entry TYPE REF TO lcl_registry_entry,
23 | END OF ts_tab.
24 | * Container for ALV tree data:
25 | DATA: gt_tab TYPE TABLE OF ts_tab.
26 |
27 | * For maintaining registry values in an an entry (ALV control):
28 | DATA: gr_table TYPE REF TO cl_gui_alv_grid.
29 | DATA: gt_value TYPE STANDARD TABLE OF lcl_registry_entry=>ts_keyval.
30 | DATA: gt_value_ori TYPE STANDARD TABLE OF lcl_registry_entry=>ts_keyval. "Original data
31 |
32 | * For splitter container
33 | DATA: gr_splitter TYPE REF TO cl_gui_easy_splitter_container.
34 |
35 | * For registry access:
36 | DATA: gr_reg_root TYPE REF TO lcl_registry_entry.
37 |
38 | DATA: gr_sel_reg_entry TYPE REF TO lcl_registry_entry. "Selected reg. entry
39 | DATA: gv_sel_node_key TYPE lvc_nkey. "Tree node key of currently selected node
40 |
41 | * Single statement to generate a selection screen
42 | PARAMETERS: dummy.
43 |
44 | *----------------------------------------------------------------------*
45 | * CLASS event_handler DEFINITION
46 | *----------------------------------------------------------------------*
47 | CLASS event_handler DEFINITION.
48 | PUBLIC SECTION.
49 | CLASS-METHODS:
50 | handle_node_expand FOR EVENT expand_nc OF cl_gui_alv_tree
51 | IMPORTING node_key sender,
52 | handle_table_toolbar FOR EVENT toolbar OF cl_gui_alv_grid
53 | IMPORTING e_object e_interactive sender,
54 | handle_table_command FOR EVENT user_command OF cl_gui_alv_grid
55 | IMPORTING e_ucomm,
56 | handle_node_selected FOR EVENT selection_changed OF cl_gui_alv_tree
57 | IMPORTING node_key,
58 | handle_tree_command FOR EVENT function_selected OF cl_gui_toolbar
59 | IMPORTING fcode.
60 | * handle_values_changed for event DATA_CHANGE of CL_GUI_ALV_GRID
61 | * importing er_data_changed e_onf4 e_onf4_before e_onf4_after e_ucomm.
62 |
63 | ENDCLASS. "event_handler DEFINITION
64 |
65 | *----------------------------------------------------------------------*
66 | * CLASS event_handler IMPLEMENTATION
67 | *----------------------------------------------------------------------*
68 | CLASS event_handler IMPLEMENTATION.
69 |
70 | * Handle commands to the tree toolbar
71 | METHOD handle_tree_command.
72 | DATA: lv_new_key TYPE string.
73 | DATA: lr_reg_entry TYPE REF TO lcl_registry_entry.
74 | DATA: lv_node_key TYPE lvc_nkey.
75 | DATA: lv_rc TYPE char1.
76 | DATA: lv_ntext TYPE lvc_value.
77 | DATA: ls_tab TYPE ts_tab.
78 |
79 | IF gr_sel_reg_entry IS NOT BOUND.
80 | MESSAGE 'Select a node from the tree first' TYPE 'I'.
81 | RETURN.
82 | ENDIF.
83 |
84 | * Create a new node under selected node, or copy a registry node on the same level
85 | IF fcode = 'INSE'.
86 |
87 | * Dialog to capture name of new node
88 | PERFORM value_input_dialog USING 'New registry entry key'(007)
89 | CHANGING lv_new_key lv_rc.
90 |
91 | * Add the new key to the current registry entry if the user accepts
92 | IF lv_rc = space.
93 | TRY.
94 | * Update the tree by adding the new node
95 | gr_sel_reg_entry->add_subentry( lv_new_key ).
96 | PERFORM refresh_subnodes USING gv_sel_node_key.
97 |
98 | CATCH lcx_registry_entry_exists.
99 | MESSAGE 'The registry entry already exists'(015) TYPE 'I'.
100 | RETURN.
101 | ENDTRY.
102 | ENDIF.
103 |
104 | * Copy the selected node at the same level
105 | ELSEIF fcode = 'COPY'.
106 |
107 | * Dialog to capture name of new node
108 | PERFORM value_input_dialog USING 'Target registry entry key'(006)
109 | CHANGING lv_new_key lv_rc.
110 |
111 | * Perform deep copy of source to target node
112 | IF lv_rc = space.
113 | DATA: lr_parent TYPE REF TO lcl_registry_entry.
114 | TRY.
115 | lr_parent = gr_sel_reg_entry->get_parent( ).
116 | lr_parent->copy_subentry( source_key = gr_sel_reg_entry->entry_id target_key = lv_new_key ).
117 |
118 | * Get the parent node in the tree to refresh it
119 | CALL METHOD gr_tree->get_parent
120 | EXPORTING
121 | i_node_key = gv_sel_node_key
122 | IMPORTING
123 | e_parent_node_key = lv_node_key.
124 |
125 | * Refresh the parent node
126 | PERFORM refresh_subnodes USING lv_node_key.
127 |
128 | CATCH lcx_registry_entry_exists.
129 | MESSAGE 'The registry entry already exists'(015) TYPE 'I'.
130 | RETURN.
131 | CATCH lcx_registry_err.
132 | MESSAGE 'Error updating registry'(017) TYPE 'I'.
133 | RETURN.
134 | ENDTRY.
135 | ENDIF.
136 |
137 | * Delete the selected node from the registry
138 | ELSEIF fcode = 'DELE'.
139 |
140 | * Prevent deleting of the root entity, which would fail anyway when we try get its parent
141 | IF gr_sel_reg_entry->internal_key = lcl_registry_entry=>registry_root.
142 | MESSAGE 'Root node cannot be deleted' TYPE 'I'.
143 | RETURN.
144 | ENDIF.
145 |
146 | CALL FUNCTION 'POPUP_TO_CONFIRM'
147 | EXPORTING
148 | titlebar = 'Confirm deletion'(009)
149 | text_question = 'Are you sure you want to delete the selected entry?'(010)
150 | display_cancel_button = abap_false
151 | IMPORTING
152 | answer = lv_rc
153 | EXCEPTIONS
154 | text_not_found = 1
155 | OTHERS = 2.
156 | IF sy-subrc <> 0.
157 | * Won't happen
158 | ENDIF.
159 |
160 | * Check that the user selected OK on the confirmation
161 | CHECK lv_rc = '1'.
162 |
163 | lr_reg_entry = gr_sel_reg_entry->get_parent( ).
164 | CHECK lr_reg_entry IS BOUND.
165 | lr_reg_entry->remove_subentry( gr_sel_reg_entry->entry_id ).
166 |
167 | * Get the parent node in the tree to refresh it
168 | CALL METHOD gr_tree->get_parent
169 | EXPORTING
170 | i_node_key = gv_sel_node_key
171 | IMPORTING
172 | e_parent_node_key = lv_node_key.
173 |
174 | * Refresh the parent node
175 | PERFORM refresh_subnodes USING lv_node_key.
176 |
177 | ENDIF.
178 |
179 | ENDMETHOD. "handle_tree_command
180 |
181 | * Handle commands on the values table
182 | METHOD handle_table_command.
183 | DATA: lv_node_key TYPE lvc_nkey.
184 | DATA: ls_tab TYPE ts_tab.
185 | DATA: lt_value TYPE lcl_registry_entry=>tt_keyval.
186 | DATA: ls_value TYPE lcl_registry_entry=>ts_keyval.
187 |
188 | * Save current values
189 | IF e_ucomm = 'SAVE'.
190 | PERFORM save_values.
191 | ENDIF.
192 | ENDMETHOD. "handle_table_command
193 |
194 | * Handle selection of a node in the tree
195 | METHOD handle_node_selected.
196 | DATA: ls_tab TYPE ts_tab.
197 | DATA: lt_val TYPE lcl_registry_entry=>tt_keyval.
198 |
199 | * Check whether data has changed before
200 | DATA: lv_answer TYPE char01.
201 | DATA: lv_refresh TYPE char01.
202 | * Check for changed data. The CHECK_CHANGED_DATA() method and
203 | * neither the DATA_CHANGED or DATA_CHANGED_FINISHED
204 | * events of CL_GUI_ALV_GRID seem to fit the bill, so we keep our own copy
205 | * of the original data and compare it
206 | IF gr_table IS BOUND.
207 | * Refresh data in local table (GT_VALUE)
208 | CALL METHOD gr_table->check_changed_data.
209 |
210 | IF gt_value NE gt_value_ori.
211 | CALL FUNCTION 'POPUP_TO_CONFIRM'
212 | EXPORTING
213 | titlebar = 'Confirm data loss'(017)
214 | text_question = 'Data has changed. Save first?'(018)
215 | display_cancel_button = abap_false
216 | IMPORTING
217 | answer = lv_answer
218 | EXCEPTIONS
219 | text_not_found = 1
220 | OTHERS = 2.
221 | IF sy-subrc <> 0.
222 | * Not going to happen; not using a text
223 | ENDIF.
224 |
225 | IF lv_answer = '1'. "Save data before moving on
226 | PERFORM save_values.
227 | ENDIF.
228 |
229 | ENDIF.
230 |
231 | ENDIF.
232 |
233 | * Set up the table
234 | IF gr_table IS NOT BOUND.
235 | PERFORM create_table.
236 | ENDIF.
237 |
238 | CALL METHOD gr_tree->get_outtab_line
239 | EXPORTING
240 | i_node_key = node_key
241 | IMPORTING
242 | e_outtab_line = ls_tab " Line of Outtab
243 | EXCEPTIONS
244 | node_not_found = 1
245 | OTHERS = 2.
246 | IF sy-subrc <> 0.
247 | MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
248 | WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
249 | ENDIF.
250 |
251 | * Read the values of the selected registry entry
252 | gt_value = ls_tab-reg_entry->get_values( ).
253 | gt_value_ori = gt_value. "Store last values
254 | * Ensure column widths are correct on every update
255 | * Settings on table
256 | * data: ls_layout type lvc_s_layo.
257 | * ls_layout-cwidth_opt = abap_true.
258 | * gr_table->set_frontend_layout( ls_layout ).
259 | gr_table->refresh_table_display( ).
260 | * Keep track of selected reg. entry for update
261 | gr_sel_reg_entry = ls_tab-reg_entry.
262 | gv_sel_node_key = node_key.
263 |
264 | ENDMETHOD. "handle_node_selected
265 |
266 | * Expand nodes of the registry tree to add sub-entries
267 | METHOD handle_node_expand.
268 | DATA: lr_reg_entry TYPE REF TO lcl_registry_entry.
269 | DATA: ls_tab TYPE ts_tab.
270 |
271 | CALL METHOD sender->get_outtab_line
272 | EXPORTING
273 | i_node_key = node_key
274 | IMPORTING
275 | e_outtab_line = ls_tab " Line of Outtab
276 | EXCEPTIONS
277 | node_not_found = 1
278 | OTHERS = 2.
279 | IF sy-subrc <> 0.
280 | MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
281 | WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
282 | ENDIF.
283 |
284 | DATA: lt_sub_entries TYPE lcl_registry_entry=>tt_keyobj.
285 | DATA: ls_sub_entry TYPE lcl_registry_entry=>ts_keyobj.
286 | DATA: lv_expander TYPE abap_bool.
287 | DATA: lv_node_text TYPE lvc_value.
288 |
289 | * Add sub-entries to selected node in tree
290 | lt_sub_entries = ls_tab-reg_entry->get_subentries( ).
291 | LOOP AT lt_sub_entries INTO ls_sub_entry.
292 |
293 | lr_reg_entry = ls_sub_entry-value.
294 | PERFORM add_node USING node_key lr_reg_entry.
295 |
296 | ENDLOOP.
297 |
298 | ENDMETHOD. "EXPAND_EMPTY_FOLDER
299 |
300 | * Modify toolbar entries for table/grid
301 | METHOD handle_table_toolbar.
302 | DATA: ls_tbe TYPE stb_button.
303 | * Keep only the local editing features
304 | LOOP AT e_object->mt_toolbar INTO ls_tbe.
305 | IF ls_tbe-function(7) NE '&LOCAL&'.
306 | DELETE e_object->mt_toolbar.
307 | ENDIF.
308 | ENDLOOP.
309 | * Add a function for saving the values
310 | ls_tbe-function = 'SAVE'.
311 | ls_tbe-icon = '@2L@'.
312 | ls_tbe-butn_type = '0'.
313 | ls_tbe-quickinfo = 'Save'.
314 | APPEND ls_tbe TO e_object->mt_toolbar.
315 | ENDMETHOD. "handle_table_toolbar
316 |
317 | ENDCLASS. "event_handler IMPLEMENTATION
318 |
319 | *&---------------------------------------------------------------------*
320 | *& Form refresh_subnodes
321 | *&---------------------------------------------------------------------*
322 | * Delete and refresh subnodes of a node
323 | *----------------------------------------------------------------------*
324 | FORM refresh_subnodes USING pv_nkey TYPE lvc_nkey.
325 | DATA: ls_tab TYPE ts_tab.
326 | DATA: ls_subentry TYPE lcl_registry_entry=>ts_keyval.
327 | DATA: lr_reg_entry TYPE REF TO lcl_registry_entry.
328 | DATA: lt_children TYPE lvc_t_nkey.
329 | DATA: lv_nkey TYPE lvc_nkey.
330 |
331 | * Delete subnodes of node. This means: getting all children and deleting
332 | * them individually!
333 | CALL METHOD gr_tree->get_children
334 | EXPORTING
335 | i_node_key = pv_nkey
336 | IMPORTING
337 | et_children = lt_children
338 | EXCEPTIONS
339 | historic_error = 1
340 | node_key_not_found = 2
341 | OTHERS = 3.
342 | IF sy-subrc <> 0.
343 | MESSAGE 'Error building tree'(014) TYPE 'E'.
344 | ENDIF.
345 |
346 | LOOP AT lt_children INTO lv_nkey.
347 |
348 | CALL METHOD gr_tree->delete_subtree
349 | EXPORTING
350 | i_node_key = lv_nkey
351 | i_update_parents_expander = abap_true
352 | EXCEPTIONS
353 | node_key_not_in_model = 1
354 | OTHERS = 2.
355 | IF sy-subrc <> 0.
356 | MESSAGE 'Error building tree'(014) TYPE 'E'.
357 | ENDIF.
358 |
359 | ENDLOOP.
360 |
361 | * With the children deleted, proceed to re-add registry entries
362 |
363 | * Get the registry entry on the node
364 | CALL METHOD gr_tree->get_outtab_line
365 | EXPORTING
366 | i_node_key = pv_nkey
367 | IMPORTING
368 | e_outtab_line = ls_tab
369 | EXCEPTIONS
370 | node_not_found = 1
371 | OTHERS = 2.
372 | IF sy-subrc NE 0.
373 | MESSAGE 'Error building tree'(014) TYPE 'E'.
374 | ENDIF.
375 | * Add a subnode for each sub-entry
376 | LOOP AT ls_tab-reg_entry->sub_entries INTO ls_subentry.
377 | lr_reg_entry = ls_tab-reg_entry->get_subentry( ls_subentry-key ).
378 | PERFORM add_node USING pv_nkey lr_reg_entry.
379 | ENDLOOP.
380 | * Expand parent node
381 | CALL METHOD gr_tree->expand_node
382 | EXPORTING
383 | i_node_key = pv_nkey
384 | EXCEPTIONS
385 | failed = 1
386 | illegal_level_count = 2
387 | cntl_system_error = 3
388 | node_not_found = 4
389 | cannot_expand_leaf = 5
390 | OTHERS = 6.
391 | IF sy-subrc <> 0.
392 | MESSAGE 'Error building tree'(014) TYPE 'E'.
393 | ENDIF.
394 | * Update tree display
395 | gr_table->refresh_table_display( ).
396 | ENDFORM. "refresh_subnodes
397 |
398 |
399 | *&---------------------------------------------------------------------*
400 | *& Form save_values
401 | *&---------------------------------------------------------------------*
402 | * Save current values in table to currently selected reg. node
403 | *----------------------------------------------------------------------*
404 | FORM save_values.
405 | IF gr_table IS BOUND AND gr_sel_reg_entry IS BOUND.
406 | DATA: lt_value TYPE lcl_registry_entry=>tt_keyval.
407 | DATA: ls_value TYPE lcl_registry_entry=>ts_keyval.
408 | * Normalize the values; duplicate keys are overwritten, with possible loss of data!
409 | LOOP AT gt_value INTO ls_value.
410 | INSERT ls_value INTO TABLE lt_value.
411 | ENDLOOP.
412 | gr_sel_reg_entry->set_values( lt_value ).
413 | TRY.
414 | gr_sel_reg_entry->save( ).
415 | CATCH lcx_registry_lock.
416 | MESSAGE 'Values have been overwritten since last change and are refreshed'(004) TYPE 'I'.
417 | gr_sel_reg_entry->reload( ).
418 | gt_value = gr_sel_reg_entry->get_values( ).
419 | ENDTRY.
420 | gr_table->refresh_table_display( ).
421 | ENDIF.
422 |
423 | ENDFORM. "save_values
424 |
425 | *&---------------------------------------------------------------------*
426 | *& Form add_node
427 | *&---------------------------------------------------------------------*
428 | * Add single node to tree
429 | *----------------------------------------------------------------------*
430 | * -->PV_NKEY Node of tree to which to add node
431 | * -->PS_TAB Table entry (with reg. entry) to add as child
432 | *----------------------------------------------------------------------*
433 | FORM add_node
434 | USING pv_nkey TYPE lvc_nkey pr_regentry TYPE REF TO lcl_registry_entry.
435 |
436 | DATA: lv_node_text TYPE lvc_value.
437 | DATA: ls_node_layout TYPE lvc_s_layn. "Layout for new nodes
438 | DATA: ls_tab TYPE ts_tab.
439 |
440 | IF pr_regentry IS NOT BOUND.
441 | MESSAGE 'Error building tree'(014) TYPE 'E'.
442 | ENDIF.
443 |
444 | ls_tab-reg_entry = pr_regentry.
445 |
446 | * Add node as folder always
447 | ls_node_layout-isfolder = abap_true.
448 | * Add expander only if there are more sub-entries
449 | IF lines( pr_regentry->get_subentry_keys( ) ) > 0.
450 | ls_node_layout-expander = abap_true.
451 | ELSE.
452 | ls_node_layout-expander = abap_false.
453 | ENDIF.
454 |
455 | lv_node_text = pr_regentry->entry_id.
456 |
457 | CALL METHOD gr_tree->add_node
458 | EXPORTING
459 | i_relat_node_key = pv_nkey
460 | i_relationship = cl_gui_column_tree=>relat_last_child
461 | is_outtab_line = ls_tab
462 | i_node_text = lv_node_text
463 | is_node_layout = ls_node_layout
464 | EXCEPTIONS
465 | relat_node_not_found = 1
466 | node_not_found = 2
467 | OTHERS = 3.
468 | IF sy-subrc <> 0.
469 | MESSAGE 'Error building tree'(014) TYPE 'E'.
470 | ENDIF.
471 |
472 | ENDFORM. "add_node
473 |
474 | *&---------------------------------------------------------------------*
475 | *& Form create_table
476 | *&---------------------------------------------------------------------*
477 | * Initialize table for showing values in a registry entry
478 | *----------------------------------------------------------------------*
479 | FORM create_table RAISING cx_salv_msg.
480 | DATA: lr_func TYPE REF TO cl_salv_functions_list.
481 | DATA: lr_cols TYPE REF TO cl_salv_columns_table.
482 |
483 | DATA: lt_fcat TYPE lvc_t_fcat.
484 | DATA: ls_fcat TYPE lvc_s_fcat.
485 |
486 | CREATE OBJECT gr_table
487 | EXPORTING
488 | i_parent = gr_splitter->bottom_right_container
489 | i_appl_events = abap_true " Register Events as Application Events
490 | * i_fcat_complete = SPACE " Boolean Variable (X=True, Space=False)
491 | EXCEPTIONS
492 | error_cntl_create = 1
493 | error_cntl_init = 2
494 | error_cntl_link = 3
495 | error_dp_create = 4
496 | OTHERS = 5.
497 | IF sy-subrc <> 0.
498 | MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
499 | WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
500 | ENDIF.
501 |
502 | * Add fields to catalog
503 | ls_fcat-fieldname = 'KEY'.
504 | ls_fcat-edit = abap_true.
505 | ls_fcat-key = abap_true.
506 | ls_fcat-scrtext_s = 'Key'(001).
507 | ls_fcat-outputlen = 35. "Because colwidth opt is not always great
508 | APPEND ls_fcat TO lt_fcat.
509 | ls_fcat-fieldname = 'VALUE'.
510 | ls_fcat-edit = abap_true.
511 | ls_fcat-key = abap_false.
512 | ls_fcat-scrtext_s = 'Value'(002).
513 | ls_fcat-outputlen = 35. "Because colwidth opt is not always great
514 | APPEND ls_fcat TO lt_fcat.
515 |
516 | gr_table->set_table_for_first_display(
517 | CHANGING
518 | it_outtab = gt_value[]
519 | it_fieldcatalog = lt_fcat
520 | EXCEPTIONS
521 | invalid_parameter_combination = 1
522 | program_error = 2
523 | too_many_lines = 3
524 | OTHERS = 4 ).
525 | IF sy-subrc <> 0.
526 | MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
527 | WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
528 | ENDIF.
529 |
530 | * Toolbar to hold only functions for editing
531 | SET HANDLER event_handler=>handle_table_toolbar FOR gr_table.
532 | SET HANDLER event_handler=>handle_table_command FOR gr_table.
533 | gr_table->set_toolbar_interactive( ).
534 |
535 | ** Settings on table
536 | * data: ls_layout type lvc_s_layo.
537 | * ls_layout-cwidth_opt = abap_true.
538 | * gr_table->set_frontend_layout( ls_layout ).
539 |
540 | ENDFORM. "create_table
541 |
542 | *&---------------------------------------------------------------------*
543 | *& Form create_tree
544 | *&---------------------------------------------------------------------*
545 | * Initialize tree showing the registry hierarchy
546 | *----------------------------------------------------------------------*
547 | FORM create_tree.
548 |
549 | DATA: lt_fcat TYPE lvc_t_fcat.
550 | DATA: ls_fcat TYPE lvc_s_fcat.
551 | DATA: lt_event TYPE cntl_simple_events,
552 | ls_event TYPE cntl_simple_event.
553 |
554 | gr_reg_root = lcl_registry_entry=>get_root( ).
555 |
556 | * Create tree
557 | CREATE OBJECT gr_tree
558 | EXPORTING
559 | parent = gr_splitter->top_left_container
560 | node_selection_mode = cl_gui_column_tree=>node_sel_mode_single
561 | item_selection = abap_false
562 | no_toolbar = abap_false
563 | no_html_header = abap_true
564 | EXCEPTIONS
565 | cntl_error = 1
566 | cntl_system_error = 2
567 | create_error = 3
568 | lifetime_error = 4
569 | illegal_node_selection_mode = 5
570 | failed = 6
571 | illegal_column_name = 7
572 | OTHERS = 8.
573 | IF sy-subrc <> 0.
574 | MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
575 | WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
576 | ENDIF.
577 |
578 | * Add key so that there is *something* in the field catalog
579 | ls_fcat-fieldname = 'KEY'.
580 | ls_fcat-no_out = abap_true.
581 | APPEND ls_fcat TO lt_fcat.
582 |
583 | CALL METHOD gr_tree->set_table_for_first_display
584 | CHANGING
585 | it_outtab = gt_tab
586 | it_fieldcatalog = lt_fcat.
587 |
588 | * Get handle on tree toolbar
589 | DATA: lt_ttb TYPE ttb_button.
590 | DATA: ls_ttb TYPE stb_button.
591 | gr_tree->get_toolbar_object( IMPORTING er_toolbar = gr_tree_toolbar ).
592 | gr_tree_toolbar->delete_all_buttons( ).
593 | * Add custom buttons for registry entry operations
594 | ls_ttb-function = 'INSE'. "Insert entry
595 | ls_ttb-icon = '@17@'. "ICON_INSERT_ROW
596 | APPEND ls_ttb TO lt_ttb.
597 | ls_ttb-function = 'DELE'. "Delete entry
598 | ls_ttb-icon = '@18@'. "ICON_DELETE_ROW
599 | APPEND ls_ttb TO lt_ttb.
600 | ls_ttb-function = 'COPY'. "Copy Entry
601 | ls_ttb-icon = '@14@'. "ICON_COPY_OBJECT
602 | APPEND ls_ttb TO lt_ttb.
603 | CALL METHOD gr_tree_toolbar->add_button_group
604 | EXPORTING
605 | data_table = lt_ttb
606 | EXCEPTIONS
607 | dp_error = 1
608 | cntb_error_fcode = 2
609 | OTHERS = 3.
610 | IF sy-subrc <> 0.
611 | MESSAGE 'Error when setting up registry toolbar'(005) TYPE 'E'.
612 | ENDIF.
613 |
614 | * Add root node
615 | PERFORM add_node USING '' gr_reg_root.
616 |
617 | * Register events and set handlers
618 | * ls_event-eventid = cl_gui_simple_tree=>eventid_node_double_click.
619 | ls_event-eventid = cl_gui_simple_tree=>eventid_selection_changed.
620 | ls_event-appl_event = 'X'.
621 | APPEND ls_event TO lt_event.
622 | ls_event-eventid = cl_gui_simple_tree=>eventid_expand_no_children.
623 | ls_event-appl_event = 'X'.
624 | APPEND ls_event TO lt_event.
625 | CALL METHOD gr_tree->set_registered_events
626 | EXPORTING
627 | events = lt_event
628 | EXCEPTIONS
629 | cntl_error = 1
630 | cntl_system_error = 2
631 | illegal_event_combination = 3.
632 | IF sy-subrc <> 0.
633 | MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
634 | WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
635 | ENDIF.
636 |
637 | SET HANDLER event_handler=>handle_node_expand FOR gr_tree.
638 | SET HANDLER event_handler=>handle_node_selected FOR gr_tree.
639 | SET HANDLER event_handler=>handle_tree_command FOR gr_tree_toolbar.
640 |
641 | CALL METHOD gr_tree->frontend_update.
642 |
643 | ENDFORM. "create_tree
644 |
645 | *&---------------------------------------------------------------------*
646 | *& Form value_input_dialog
647 | *&---------------------------------------------------------------------*
648 | * Get single value from user
649 | *----------------------------------------------------------------------*
650 | FORM value_input_dialog USING title CHANGING value returncode.
651 | DATA: lt_fld TYPE TABLE OF sval.
652 | DATA: ls_fld TYPE sval.
653 |
654 | ls_fld-tabname = 'OJFIELDS'.
655 | ls_fld-fieldname = 'INPUT'.
656 | APPEND ls_fld TO lt_fld.
657 |
658 | CALL FUNCTION 'POPUP_GET_VALUES'
659 | EXPORTING
660 | no_value_check = abap_true
661 | popup_title = title
662 | IMPORTING
663 | returncode = returncode
664 | TABLES
665 | fields = lt_fld
666 | EXCEPTIONS
667 | error_in_fields = 1
668 | OTHERS = 2.
669 | IF sy-subrc <> 0.
670 | MESSAGE 'Error during request for value'(008) TYPE 'E'.
671 | ENDIF.
672 |
673 | READ TABLE lt_fld INTO ls_fld INDEX 1.
674 | value = ls_fld-value.
675 |
676 | ENDFORM. "value_input_dialog
677 |
678 | START-OF-SELECTION.
679 |
680 |
681 | AT SELECTION-SCREEN OUTPUT.
682 | * Disable Execute and Save functions on report selection screen
683 | PERFORM insert_into_excl(rsdbrunt) USING 'ONLI'.
684 | PERFORM insert_into_excl(rsdbrunt) USING 'SPOS'.
685 |
686 | * Initialize the display on the first dynpro roundtrip
687 | IF gr_splitter IS NOT BOUND.
688 | DATA: gv_dynnr TYPE sydynnr.
689 | DATA: gv_repid TYPE syrepid.
690 | gv_dynnr = sy-dynnr.
691 | gv_repid = sy-repid.
692 | CREATE OBJECT gr_splitter
693 | EXPORTING
694 | link_dynnr = gv_dynnr
695 | link_repid = gv_repid
696 | parent = cl_gui_easy_splitter_container=>default_screen
697 | orientation = 1 " Orientation: 0 = Vertical, 1 = Horizontal
698 | sash_position = 30 " Position of Splitter Bar (in Percent)
699 | with_border = 0 " With Border = 1; Without Border = 0
700 | EXCEPTIONS
701 | cntl_error = 1
702 | cntl_system_error = 2
703 | OTHERS = 3.
704 |
705 | IF sy-subrc <> 0.
706 | EXIT.
707 | ENDIF.
708 |
709 | PERFORM create_tree.
710 |
711 | * Table creation is deferred until the first node is selected
712 |
713 | ENDIF.
714 |
--------------------------------------------------------------------------------
/src/yy_lib_turtle.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Include YY_LIB_TURTLE
3 | *&---------------------------------------------------------------------*
4 | * Ported from https://github.com/FreHu/abap-turtle-graphics
5 |
6 | "TYPES tv_real TYPE decfloat34. " real data type
7 |
8 | CLASS lcx_turtle_problem DEFINITION CREATE PRIVATE
9 | INHERITING FROM cx_no_check.
10 |
11 | PUBLIC SECTION.
12 | CLASS-METHODS raise IMPORTING text TYPE string.
13 | METHODS constructor IMPORTING text TYPE string
14 | previous TYPE REF TO cx_root OPTIONAL.
15 | PRIVATE SECTION.
16 | DATA text TYPE string.
17 | ENDCLASS.
18 |
19 | CLASS lcx_turtle_problem IMPLEMENTATION.
20 |
21 | METHOD raise.
22 | RAISE EXCEPTION TYPE lcx_turtle_problem EXPORTING text = text.
23 | ENDMETHOD.
24 |
25 | METHOD constructor ##ADT_SUPPRESS_GENERATION.
26 | super->constructor( ).
27 | me->text = text.
28 | me->previous = previous.
29 | ENDMETHOD.
30 | ENDCLASS.
31 |
32 | CLASS lcl_turtle_math DEFINITION.
33 | PUBLIC SECTION.
34 | TYPES numbers_i TYPE STANDARD TABLE OF tv_int WITH DEFAULT KEY.
35 |
36 | CLASS-METHODS find_max_int
37 | IMPORTING numbers TYPE numbers_i
38 | RETURNING VALUE(result) TYPE tv_int.
39 | ENDCLASS.
40 |
41 | CLASS lcl_turtle_math IMPLEMENTATION.
42 |
43 | METHOD find_max_int.
44 | DATA(max) = numbers[ 1 ].
45 | LOOP AT numbers ASSIGNING FIELD-SYMBOL() FROM 2.
46 | CHECK > max.
47 | max = .
48 | ENDLOOP.
49 |
50 | result = max.
51 | ENDMETHOD.
52 | ENDCLASS.
53 |
54 | CLASS lcl_turtle_convert DEFINITION.
55 | PUBLIC SECTION.
56 | CLASS-METHODS degrees_to_radians
57 | IMPORTING degrees TYPE tv_real
58 | RETURNING VALUE(radians) TYPE tv_real.
59 |
60 | CLASS-METHODS radians_to_degrees
61 | IMPORTING radians TYPE tv_real
62 | RETURNING VALUE(degrees) TYPE tv_real.
63 | ENDCLASS.
64 |
65 | CLASS lcl_turtle_convert IMPLEMENTATION.
66 |
67 | METHOD degrees_to_radians.
68 | radians = degrees * c_pi / 180.
69 | ENDMETHOD.
70 |
71 | METHOD radians_to_degrees.
72 | degrees = radians * 180 / c_pi.
73 | ENDMETHOD.
74 | ENDCLASS.
75 |
76 | CLASS lcl_number_range DEFINITION.
77 | PUBLIC SECTION.
78 | TYPES number_range TYPE STANDARD TABLE OF i WITH EMPTY KEY.
79 |
80 | "! Returns the list of numbers <min, max).
81 | "! This method repeats the mistake of Python 2.x and will consume a lot of memory if used with large ranges
82 | CLASS-METHODS get
83 | IMPORTING min TYPE i
84 | max TYPE i
85 | RETURNING VALUE(result) TYPE number_range.
86 | ENDCLASS.
87 |
88 | CLASS lcl_number_range IMPLEMENTATION.
89 |
90 | METHOD get.
91 | DATA(i) = min.
92 | WHILE i < max.
93 | APPEND i TO result.
94 | i = i + 1.
95 | ENDWHILE.
96 | ENDMETHOD.
97 | ENDCLASS.
98 |
99 | CLASS lcl_turtle_colors DEFINITION.
100 | PUBLIC SECTION.
101 | TYPES: rgb_hex_color TYPE string,
102 | rgb_hex_colors TYPE STANDARD TABLE OF rgb_hex_color WITH EMPTY KEY.
103 |
104 | TYPES: BEGIN OF t_pen,
105 | stroke_color TYPE rgb_hex_color,
106 | stroke_width TYPE i,
107 | fill_color TYPE rgb_hex_color,
108 | is_up TYPE abap_bool,
109 | END OF t_pen.
110 |
111 | CLASS-METHODS class_constructor.
112 | CLASS-METHODS get_random_color
113 | IMPORTING colors TYPE rgb_hex_colors
114 | RETURNING VALUE(color) TYPE rgb_hex_color.
115 |
116 | CLASS-DATA default_color_scheme TYPE rgb_hex_colors.
117 | CLASS-DATA default_pen TYPE t_pen.
118 | PROTECTED SECTION.
119 | PRIVATE SECTION.
120 | CLASS-DATA random TYPE REF TO cl_abap_random.
121 | ENDCLASS.
122 |
123 |
124 | CLASS lcl_turtle_colors IMPLEMENTATION.
125 |
126 | METHOD class_constructor.
127 | default_color_scheme = VALUE #(
128 | ( `#8a295c` )
129 | ( `#5bbc6d` )
130 | ( `#cb72d3` )
131 | ( `#a8b03f` )
132 | ( `#6973d8` )
133 | ( `#c38138` )
134 | ( `#543788` )
135 | ( `#768a3c` )
136 | ( `#ac4595` )
137 | ( `#47bf9c` )
138 | ( `#db6697` )
139 | ( `#5f8dd3` )
140 | ( `#b64e37` )
141 | ( `#c287d1` )
142 | ( `#ba4758` ) ).
143 |
144 | random = cl_abap_random=>create( seed = 42 ).
145 |
146 | default_pen = VALUE t_pen( stroke_width = 1
147 | stroke_color = `#FF0000`
148 | is_up = abap_false ).
149 | ENDMETHOD.
150 |
151 | METHOD get_random_color.
152 | DATA(random_index) = random->intinrange( low = 1 high = lines( colors ) ).
153 | color = colors[ random_index ].
154 | ENDMETHOD.
155 | ENDCLASS.
156 |
157 | CLASS lcl_turtle DEFINITION DEFERRED.
158 |
159 | CLASS lcl_turtle_svg DEFINITION CREATE PRIVATE.
160 | PUBLIC SECTION.
161 | TYPES:
162 | BEGIN OF t_point,
163 | x TYPE i,
164 | y TYPE i,
165 | END OF t_point,
166 | t_points TYPE STANDARD TABLE OF t_point WITH DEFAULT KEY.
167 |
168 | TYPES:
169 | BEGIN OF line_params,
170 | x_from TYPE i,
171 | y_from TYPE i,
172 | x_to TYPE i,
173 | y_to TYPE i,
174 | END OF line_params,
175 |
176 |
177 | BEGIN OF polygon_params,
178 | points TYPE t_points,
179 | END OF polygon_params,
180 | polyline_params TYPE polygon_params,
181 |
182 | BEGIN OF text_params,
183 | x TYPE i,
184 | y TYPE i,
185 | text TYPE string,
186 | END OF text_params,
187 |
188 | BEGIN OF circle_params,
189 | center_x TYPE i,
190 | center_y TYPE i,
191 | radius TYPE i,
192 | END OF circle_params.
193 |
194 | CLASS-METHODS new IMPORTING turtle TYPE REF TO lcl_turtle
195 | RETURNING VALUE(result) TYPE REF TO lcl_turtle_svg.
196 |
197 | METHODS: line IMPORTING params TYPE line_params
198 | RETURNING VALUE(svg_line) TYPE string,
199 |
200 | polygon IMPORTING params TYPE polygon_params
201 | RETURNING VALUE(svg_polygon) TYPE string,
202 |
203 | polyline IMPORTING params TYPE polyline_params
204 | RETURNING VALUE(svg_polyline) TYPE string,
205 |
206 | text IMPORTING params TYPE text_params
207 | RETURNING VALUE(svg_text) TYPE string,
208 |
209 | circle IMPORTING params TYPE circle_params
210 | RETURNING VALUE(svg_circle) TYPE string.
211 |
212 | PROTECTED SECTION.
213 | DATA turtle TYPE REF TO lcl_turtle.
214 |
215 | METHODS constructor IMPORTING turtle TYPE REF TO lcl_turtle.
216 | ENDCLASS.
217 |
218 | CLASS lcl_turtle DEFINITION CREATE PRIVATE.
219 | PUBLIC SECTION.
220 | CONSTANTS:
221 | BEGIN OF defaults,
222 | height TYPE tv_int VALUE 800,
223 | width TYPE tv_int VALUE 600,
224 | title TYPE string VALUE `abapTurtle`,
225 | END OF defaults.
226 |
227 | TYPES: t_point TYPE lcl_turtle_svg=>t_point,
228 | t_points TYPE lcl_turtle_svg=>t_points.
229 |
230 | TYPES t_pen TYPE lcl_turtle_colors=>t_pen.
231 | TYPES rgb_hex_color TYPE lcl_turtle_colors=>rgb_hex_color.
232 | TYPES rgb_hex_colors TYPE lcl_turtle_colors=>rgb_hex_colors.
233 |
234 | TYPES:
235 | BEGIN OF turtle_position,
236 | x TYPE tv_int,
237 | y TYPE tv_int,
238 | angle TYPE tv_real,
239 | END OF turtle_position.
240 |
241 | TYPES multiple_turtles TYPE STANDARD TABLE OF REF TO lcl_turtle.
242 |
243 | CLASS-METHODS new
244 | IMPORTING height TYPE tv_int DEFAULT defaults-height
245 | width TYPE tv_int DEFAULT defaults-width
246 | background_color TYPE rgb_hex_color OPTIONAL
247 | title TYPE string DEFAULT defaults-title
248 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
249 |
250 | "! Creates a new turtle based on an existing instance. The position, angle and pen are preserved.
251 | "! Does not preserve content.
252 | METHODS clone RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
253 |
254 | "! Merges drawings of multiple turtles into one.
255 | CLASS-METHODS compose
256 | IMPORTING turtles TYPE multiple_turtles
257 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
258 |
259 | METHODS constructor
260 | IMPORTING height TYPE tv_int
261 | width TYPE tv_int
262 | background_color TYPE rgb_hex_color OPTIONAL
263 | title TYPE string.
264 |
265 | METHODS right
266 | IMPORTING degrees TYPE tv_real
267 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
268 |
269 | METHODS left IMPORTING degrees TYPE tv_real
270 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
271 |
272 | METHODS set_pen IMPORTING pen TYPE t_pen
273 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
274 |
275 | METHODS goto
276 | IMPORTING x TYPE tv_int
277 | y TYPE tv_int
278 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
279 |
280 | METHODS set_angle IMPORTING angle TYPE tv_real.
281 |
282 | METHODS forward IMPORTING how_far TYPE tv_int
283 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
284 |
285 | METHODS to_offset
286 | IMPORTING delta_x TYPE numeric
287 | delta_y TYPE numeric
288 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
289 |
290 | METHODS back IMPORTING how_far TYPE tv_int
291 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
292 |
293 | METHODS pen_up RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
294 |
295 | METHODS pen_down RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
296 |
297 | METHODS show
298 | IMPORTING size TYPE string DEFAULT cl_abap_browser=>xlarge
299 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
300 |
301 | METHODS polygon_flower IMPORTING number_of_polygons TYPE tv_int
302 | polygon_sides TYPE tv_int
303 | side_length TYPE tv_int
304 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
305 |
306 | METHODS filled_square IMPORTING side_length TYPE tv_int
307 | start TYPE t_point
308 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
309 |
310 | METHODS regular_polygon IMPORTING num_sides TYPE tv_int
311 | side_length TYPE tv_int
312 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
313 |
314 | METHODS download
315 | IMPORTING filename TYPE string DEFAULT `abap-turtle.html`.
316 |
317 | METHODS enable_random_colors.
318 | METHODS disable_random_colors.
319 |
320 | METHODS get_svg RETURNING VALUE(svg) TYPE string.
321 | METHODS append_svg IMPORTING svg_to_append TYPE string.
322 |
323 | METHODS:
324 | get_position RETURNING VALUE(result) TYPE turtle_position,
325 | set_position IMPORTING position TYPE turtle_position,
326 | set_color_scheme IMPORTING color_scheme TYPE rgb_hex_colors,
327 | set_width IMPORTING width TYPE tv_int,
328 | set_height IMPORTING height TYPE tv_int,
329 | set_svg IMPORTING svg TYPE string.
330 |
331 | DATA: title TYPE string READ-ONLY,
332 | svg TYPE string READ-ONLY,
333 | width TYPE tv_int READ-ONLY,
334 | height TYPE tv_int READ-ONLY,
335 | position TYPE turtle_position READ-ONLY,
336 | pen TYPE t_pen READ-ONLY,
337 | color_scheme TYPE rgb_hex_colors READ-ONLY,
338 | svg_builder TYPE REF TO lcl_turtle_svg READ-ONLY.
339 |
340 | PROTECTED SECTION.
341 | PRIVATE SECTION.
342 | DATA use_random_colors TYPE abap_bool.
343 |
344 | METHODS get_html RETURNING VALUE(html) TYPE string.
345 |
346 | METHODS line
347 | IMPORTING x_from TYPE tv_int
348 | y_from TYPE tv_int
349 | x_to TYPE tv_int
350 | y_to TYPE tv_int
351 | RETURNING VALUE(turtle) TYPE REF TO lcl_turtle.
352 | ENDCLASS.
353 |
354 | CLASS lcl_turtle IMPLEMENTATION.
355 |
356 | METHOD back.
357 | right( degrees = 180 ).
358 | forward( how_far ).
359 | right( degrees = 180 ).
360 | ENDMETHOD.
361 |
362 | METHOD constructor.
363 | me->width = width.
364 | me->height = height.
365 | me->pen = lcl_turtle_colors=>default_pen.
366 | me->color_scheme = lcl_turtle_colors=>default_color_scheme.
367 | me->use_random_colors = abap_true.
368 | me->title = title.
369 | me->svg_builder = lcl_turtle_svg=>new( me ).
370 |
371 | IF background_color IS NOT INITIAL.
372 | me->set_pen( VALUE #( fill_color = background_color ) ).
373 | DATA(side_length) = 100.
374 |
375 | DATA(points) = VALUE t_points( ( x = 0 y = 0 )
376 | ( x = 0 + width y = 0 )
377 | ( x = 0 + width y = 0 + height )
378 | ( x = 0 y = 0 + height ) ).
379 |
380 | me->append_svg( me->svg_builder->polyline( VALUE #( points = points ) ) ).
381 | ENDIF.
382 |
383 | me->pen = VALUE #( stroke_width = 1
384 | stroke_color = `#FF0000`
385 | is_up = abap_false ).
386 | ENDMETHOD.
387 |
388 | METHOD disable_random_colors.
389 | me->use_random_colors = abap_false.
390 | ENDMETHOD.
391 |
392 | METHOD download.
393 |
394 | DATA(file_name) = filename.
395 | DATA(path) = ``.
396 | DATA(full_path) = ``.
397 |
398 | cl_gui_frontend_services=>file_save_dialog(
399 | EXPORTING
400 | default_extension = `html`
401 | default_file_name = filename
402 | initial_directory = ``
403 | CHANGING
404 | filename = file_name
405 | path = path
406 | fullpath = full_path
407 | EXCEPTIONS
408 | OTHERS = 1 ).
409 |
410 | IF sy-subrc <> 0.
411 | MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
412 | WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
413 | ENDIF.
414 |
415 | SPLIT me->get_html( ) AT |\r\n| INTO TABLE DATA(lines).
416 | cl_gui_frontend_services=>gui_download(
417 | EXPORTING
418 | filename = file_name
419 | CHANGING
420 | data_tab = lines
421 | EXCEPTIONS OTHERS = 1 ).
422 |
423 | IF sy-subrc <> 0.
424 | MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
425 | WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
426 | ENDIF.
427 |
428 | ENDMETHOD.
429 |
430 | METHOD enable_random_colors.
431 | me->use_random_colors = abap_true.
432 | ENDMETHOD.
433 |
434 | METHOD to_offset.
435 | DATA(old_position) = position.
436 | DATA(new_position) = VALUE turtle_position( x = round( val = old_position-x + delta_x dec = 0 )
437 | y = round( val = old_position-y + delta_y dec = 0 )
438 | angle = old_position-angle ).
439 | IF pen-is_up = abap_false.
440 | me->line( x_from = position-x
441 | y_from = position-y
442 | x_to = new_position-x
443 | y_to = new_position-y ).
444 | ENDIF.
445 |
446 | set_position( new_position ).
447 |
448 | turtle = me.
449 | ENDMETHOD.
450 |
451 | METHOD forward.
452 | DATA(angle) = CONV f( lcl_turtle_convert=>degrees_to_radians( position-angle ) ).
453 |
454 | turtle = to_offset( delta_x = how_far * cos( angle )
455 | delta_y = how_far * sin( angle ) ).
456 | ENDMETHOD.
457 |
458 | METHOD get_html.
459 | html = |abapTurtle
|.
460 | ENDMETHOD.
461 |
462 | METHOD get_position.
463 | result = me->position.
464 | ENDMETHOD.
465 |
466 | METHOD get_svg.
467 | svg = me->svg.
468 | ENDMETHOD.
469 |
470 | METHOD append_svg.
471 | svg = svg && svg_to_append.
472 | ENDMETHOD.
473 |
474 | METHOD goto.
475 | position-x = x.
476 | position-y = y.
477 | turtle = me.
478 | ENDMETHOD.
479 |
480 | METHOD left.
481 | position-angle = position-angle - degrees.
482 | position-angle = position-angle MOD 360.
483 | turtle = me.
484 | ENDMETHOD.
485 |
486 | METHOD line.
487 |
488 | IF use_random_colors = abap_true.
489 | pen-stroke_color = lcl_turtle_colors=>get_random_color( me->color_scheme ).
490 | ENDIF.
491 |
492 | svg = svg && ||.
494 |
495 | turtle = me.
496 | ENDMETHOD.
497 |
498 | METHOD new.
499 | turtle = NEW lcl_turtle( width = width
500 | height = height
501 | background_color = background_color
502 | title = title ).
503 | ENDMETHOD.
504 |
505 | METHOD clone.
506 | turtle = NEW #( width = width
507 | height = height
508 | title = title ).
509 |
510 | turtle->set_pen( pen ).
511 | turtle->set_color_scheme( color_scheme ).
512 | turtle->set_position( position ).
513 | turtle->set_angle( position-angle ).
514 | ENDMETHOD.
515 |
516 | METHOD compose.
517 |
518 | IF lines( turtles ) < 1.
519 | lcx_turtle_problem=>raise( `Not enough turtles to compose anything.` ).
520 | ENDIF.
521 |
522 | " start where the last one left off
523 | DATA(lo_turtle) = turtles[ lines( turtles ) ].
524 | turtle = lo_turtle->clone( ).
525 |
526 | " new image size is the largest of composed turtles
527 | DATA(new_width) = lcl_turtle_math=>find_max_int(
528 | VALUE #( FOR IN turtles ( ->width ) ) ).
529 |
530 | DATA(new_height) = lcl_turtle_math=>find_max_int(
531 | VALUE #( FOR IN turtles ( ->height ) ) ).
532 |
533 | turtle->set_height( new_height ).
534 | turtle->set_width( new_width ).
535 |
536 | DATA(composed_svg) = REDUCE string( INIT result = ``
537 | FOR