diff --git a/src/abap2xlsx/foo.txt b/src/abap2xlsx/foo.txt
deleted file mode 100644
index e69de29..0000000
diff --git a/src/abap2xlsx/package.devc.xml b/src/abap2xlsx/package.devc.xml
new file mode 100644
index 0000000..8298ba0
--- /dev/null
+++ b/src/abap2xlsx/package.devc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+ Objects which cannot work in SAP Cloud
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb.clas.abap b/src/abap2xlsx/ycl_ecb.clas.abap
new file mode 100644
index 0000000..e9196b6
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb.clas.abap
@@ -0,0 +1,700 @@
+CLASS ycl_ecb DEFINITION
+ PUBLIC
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+
+*"* public components of class ZCL_EXCEL
+*"* do not include other source files here!!!
+ INTERFACES yif_ecb_book_properties .
+ INTERFACES yif_ecb_book_protection .
+ INTERFACES yif_ecb_book_vba_project .
+
+ DATA legacy_palette TYPE REF TO ycl_ecb_legacy_palette READ-ONLY .
+ DATA security TYPE REF TO ycl_ecb_security .
+ DATA use_template TYPE abap_bool .
+ CONSTANTS version TYPE c LENGTH 10 VALUE '7.16.0'. "#EC NOTEXT
+
+ METHODS add_new_autofilter
+ IMPORTING
+ !io_sheet TYPE REF TO ycl_ecb_worksheet
+ RETURNING
+ VALUE(ro_autofilter) TYPE REF TO ycl_ecb_autofilter
+ RAISING
+ ycx_ecb .
+ METHODS add_new_comment
+ RETURNING
+ VALUE(eo_comment) TYPE REF TO ycl_ecb_comment .
+ METHODS add_new_drawing
+ IMPORTING
+ !ip_type TYPE yecb_drawing_type DEFAULT ycl_ecb_drawing=>type_image
+ !ip_title TYPE clike OPTIONAL
+ RETURNING
+ VALUE(eo_drawing) TYPE REF TO ycl_ecb_drawing .
+ METHODS add_new_range
+ RETURNING
+ VALUE(eo_range) TYPE REF TO ycl_ecb_range .
+ METHODS add_new_style
+ IMPORTING
+ !ip_guid TYPE yecb_cell_style OPTIONAL
+ !io_clone_of TYPE REF TO ycl_ecb_style OPTIONAL
+ PREFERRED PARAMETER !ip_guid
+ RETURNING
+ VALUE(eo_style) TYPE REF TO ycl_ecb_style .
+ METHODS add_new_worksheet
+ IMPORTING
+ !ip_title TYPE yecb_sheet_title OPTIONAL
+ RETURNING
+ VALUE(eo_worksheet) TYPE REF TO ycl_ecb_worksheet
+ RAISING
+ ycx_ecb .
+ METHODS add_static_styles .
+ METHODS constructor .
+ METHODS delete_worksheet
+ IMPORTING
+ !io_worksheet TYPE REF TO ycl_ecb_worksheet
+ RAISING
+ ycx_ecb .
+ METHODS delete_worksheet_by_index
+ IMPORTING
+ !iv_index TYPE numeric
+ RAISING
+ ycx_ecb .
+ METHODS delete_worksheet_by_name
+ IMPORTING
+ !iv_title TYPE clike
+ RAISING
+ ycx_ecb .
+ METHODS get_active_sheet_index
+ RETURNING
+ VALUE(r_active_worksheet) TYPE yecb_active_worksheet .
+ METHODS get_active_worksheet
+ RETURNING
+ VALUE(eo_worksheet) TYPE REF TO ycl_ecb_worksheet .
+ METHODS get_autofilters_reference
+ RETURNING
+ VALUE(ro_autofilters) TYPE REF TO ycl_ecb_autofilters .
+ METHODS get_default_style
+ RETURNING
+ VALUE(ep_style) TYPE yecb_cell_style .
+ METHODS get_drawings_iterator
+ IMPORTING
+ !ip_type TYPE yecb_drawing_type
+ RETURNING
+ VALUE(eo_iterator) TYPE REF TO ycl_ecb_collection_iterator .
+ METHODS get_next_table_id
+ RETURNING
+ VALUE(ep_id) TYPE i .
+ METHODS get_ranges_iterator
+ RETURNING
+ VALUE(eo_iterator) TYPE REF TO ycl_ecb_collection_iterator .
+ METHODS get_static_cellstyle_guid
+ IMPORTING
+ !ip_cstyle_complete TYPE yecb_s_cstyle_complete
+ !ip_cstylex_complete TYPE yecb_s_cstylex_complete
+ RETURNING
+ VALUE(ep_guid) TYPE yecb_cell_style .
+ METHODS get_styles_iterator
+ RETURNING
+ VALUE(eo_iterator) TYPE REF TO ycl_ecb_collection_iterator .
+ METHODS get_style_index_in_styles
+ IMPORTING
+ !ip_guid TYPE yecb_cell_style
+ RETURNING
+ VALUE(ep_index) TYPE i
+ RAISING
+ ycx_ecb .
+ METHODS get_style_to_guid
+ IMPORTING
+ !ip_guid TYPE yecb_cell_style
+ RETURNING
+ VALUE(ep_stylemapping) TYPE yecb_s_stylemapping
+ RAISING
+ ycx_ecb .
+ METHODS get_theme
+ EXPORTING
+ !eo_theme TYPE REF TO ycl_ecb_theme .
+ METHODS get_worksheets_iterator
+ RETURNING
+ VALUE(eo_iterator) TYPE REF TO ycl_ecb_collection_iterator .
+ METHODS get_worksheets_name
+ RETURNING
+ VALUE(ep_name) TYPE yecb_worksheets_name .
+ METHODS get_worksheets_size
+ RETURNING
+ VALUE(ep_size) TYPE i .
+ METHODS get_worksheet_by_index
+ IMPORTING
+ !iv_index TYPE numeric
+ RETURNING
+ VALUE(eo_worksheet) TYPE REF TO ycl_ecb_worksheet .
+ METHODS get_worksheet_by_name
+ IMPORTING
+ !ip_sheet_name TYPE yecb_sheet_title
+ RETURNING
+ VALUE(eo_worksheet) TYPE REF TO ycl_ecb_worksheet .
+ METHODS set_active_sheet_index
+ IMPORTING
+ !i_active_worksheet TYPE yecb_active_worksheet
+ RAISING
+ ycx_ecb .
+ METHODS set_active_sheet_index_by_name
+ IMPORTING
+ !i_worksheet_name TYPE yecb_worksheets_name .
+ METHODS set_default_style
+ IMPORTING
+ !ip_style TYPE yecb_cell_style
+ RAISING
+ ycx_ecb .
+ METHODS set_theme
+ IMPORTING
+ !io_theme TYPE REF TO ycl_ecb_theme .
+ METHODS fill_template
+ IMPORTING
+ !iv_data TYPE REF TO ycl_ecb_template_data
+ RAISING
+ ycx_ecb .
+ PROTECTED SECTION.
+
+ DATA worksheets TYPE REF TO ycl_ecb_worksheets .
+ PRIVATE SECTION.
+
+ DATA autofilters TYPE REF TO ycl_ecb_autofilters .
+ DATA charts TYPE REF TO ycl_ecb_drawings .
+ DATA default_style TYPE yecb_cell_style .
+*"* private components of class ZCL_EXCEL
+*"* do not include other source files here!!!
+ DATA drawings TYPE REF TO ycl_ecb_drawings .
+ DATA ranges TYPE REF TO ycl_ecb_ranges .
+ DATA styles TYPE REF TO ycl_ecb_styles .
+ DATA t_stylemapping1 TYPE yecb_t_stylemapping1 .
+ DATA t_stylemapping2 TYPE yecb_t_stylemapping2 .
+ DATA theme TYPE REF TO ycl_ecb_theme .
+ DATA comments TYPE REF TO ycl_ecb_comments .
+
+ METHODS get_style_from_guid
+ IMPORTING
+ !ip_guid TYPE yecb_cell_style
+ RETURNING
+ VALUE(eo_style) TYPE REF TO ycl_ecb_style .
+ METHODS stylemapping_dynamic_style
+ IMPORTING
+ !ip_style TYPE REF TO ycl_ecb_style
+ RETURNING
+ VALUE(eo_style2) TYPE yecb_s_stylemapping .
+ENDCLASS.
+
+
+
+CLASS ycl_ecb IMPLEMENTATION.
+
+
+ METHOD add_new_autofilter.
+* Check for autofilter reference: new or overwrite; only one per sheet
+ ro_autofilter = autofilters->add( io_sheet ) .
+ ENDMETHOD.
+
+
+ METHOD add_new_comment.
+ CREATE OBJECT eo_comment.
+
+ comments->add( eo_comment ).
+ ENDMETHOD.
+
+
+ METHOD add_new_drawing.
+* Create default blank worksheet
+ CREATE OBJECT eo_drawing
+ EXPORTING
+ ip_type = ip_type
+ ip_title = ip_title.
+
+ CASE ip_type.
+ WHEN 'image'.
+ drawings->add( eo_drawing ).
+ WHEN 'hd_ft'.
+ drawings->add( eo_drawing ).
+ WHEN 'chart'.
+ charts->add( eo_drawing ).
+ ENDCASE.
+ ENDMETHOD.
+
+
+ METHOD add_new_range.
+* Create default blank range
+ CREATE OBJECT eo_range.
+ ranges->add( eo_range ).
+ ENDMETHOD.
+
+
+ METHOD add_new_style.
+* Start of deletion # issue 139 - Dateretention of cellstyles
+* CREATE OBJECT eo_style.
+* styles->add( eo_style ).
+* End of deletion # issue 139 - Dateretention of cellstyles
+* Start of insertion # issue 139 - Dateretention of cellstyles
+* Create default style
+ CREATE OBJECT eo_style
+ EXPORTING
+ ip_guid = ip_guid
+ io_clone_of = io_clone_of.
+ styles->add( eo_style ).
+
+ DATA: style2 TYPE yecb_s_stylemapping.
+* Copy to new representations
+ style2 = stylemapping_dynamic_style( eo_style ).
+ INSERT style2 INTO TABLE t_stylemapping1.
+ INSERT style2 INTO TABLE t_stylemapping2.
+* End of insertion # issue 139 - Dateretention of cellstyles
+
+ ENDMETHOD.
+
+
+ METHOD add_new_worksheet.
+
+* Create default blank worksheet
+ CREATE OBJECT eo_worksheet
+ EXPORTING
+ ip_excel = me
+ ip_title = ip_title.
+
+ worksheets->add( eo_worksheet ).
+ worksheets->active_worksheet = worksheets->size( ).
+ ENDMETHOD.
+
+
+ METHOD add_static_styles.
+ " # issue 139
+ FIELD-SYMBOLS: LIKE LINE OF t_stylemapping1,
+ LIKE LINE OF t_stylemapping2.
+ DATA: style TYPE REF TO ycl_ecb_style.
+
+ LOOP AT me->t_stylemapping1 ASSIGNING WHERE added_to_iterator IS INITIAL.
+ READ TABLE me->t_stylemapping2 ASSIGNING WITH TABLE KEY guid = -guid.
+ CHECK sy-subrc = 0. " Should always be true since these tables are being filled parallel
+
+ style = me->add_new_style( -guid ).
+
+ ycl_ecb_common=>recursive_struct_to_class( EXPORTING i_source = -complete_style
+ i_sourcex = -complete_stylex
+ CHANGING e_target = style ).
+
+ ENDLOOP.
+ ENDMETHOD.
+
+
+ METHOD constructor.
+ DATA: lo_style TYPE REF TO ycl_ecb_style.
+
+* Inizialize instance objects
+ CREATE OBJECT security.
+ CREATE OBJECT worksheets.
+ CREATE OBJECT ranges.
+ CREATE OBJECT styles.
+ CREATE OBJECT drawings
+ EXPORTING
+ ip_type = ycl_ecb_drawing=>type_image.
+ CREATE OBJECT charts
+ EXPORTING
+ ip_type = ycl_ecb_drawing=>type_chart.
+ CREATE OBJECT comments.
+ CREATE OBJECT legacy_palette.
+ CREATE OBJECT autofilters.
+
+ me->yif_ecb_book_protection~initialize( ).
+ me->yif_ecb_book_properties~initialize( ).
+
+ TRY.
+ me->add_new_worksheet( ).
+ CATCH ycx_ecb. " suppress syntax check error
+ ASSERT 1 = 2. " some error processing anyway
+ ENDTRY.
+
+ me->add_new_style( ). " Standard style
+ lo_style = me->add_new_style( ). " Standard style with fill gray125
+ lo_style->fill->filltype = ycl_ecb_style_fill=>c_fill_pattern_gray125.
+
+ ENDMETHOD.
+
+
+ METHOD delete_worksheet.
+
+ DATA: lo_worksheet TYPE REF TO ycl_ecb_worksheet,
+ l_size TYPE i,
+ lv_errormessage TYPE string.
+
+ l_size = get_worksheets_size( ).
+ IF l_size = 1. " Only 1 worksheet left --> check whether this is the worksheet to be deleted
+ lo_worksheet = me->get_worksheet_by_index( 1 ).
+ IF lo_worksheet = io_worksheet.
+ lv_errormessage = 'Deleting last remaining worksheet is not allowed'(002).
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDIF.
+ ENDIF.
+
+ me->worksheets->remove( io_worksheet ).
+
+ ENDMETHOD.
+
+
+ METHOD delete_worksheet_by_index.
+
+ DATA: lo_worksheet TYPE REF TO ycl_ecb_worksheet,
+ lv_errormessage TYPE string.
+
+ lo_worksheet = me->get_worksheet_by_index( iv_index ).
+ IF lo_worksheet IS NOT BOUND.
+ lv_errormessage = 'Worksheet not existing'(001).
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDIF.
+ me->delete_worksheet( lo_worksheet ).
+
+ ENDMETHOD.
+
+
+ METHOD delete_worksheet_by_name.
+
+ DATA: lo_worksheet TYPE REF TO ycl_ecb_worksheet,
+ lv_errormessage TYPE string.
+
+ lo_worksheet = me->get_worksheet_by_name( iv_title ).
+ IF lo_worksheet IS NOT BOUND.
+ lv_errormessage = 'Worksheet not existing'(001).
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDIF.
+ me->delete_worksheet( lo_worksheet ).
+
+ ENDMETHOD.
+
+
+ METHOD fill_template.
+
+ DATA: lo_template_filler TYPE REF TO ycl_ecb_fill_template.
+
+ FIELD-SYMBOLS:
+ TYPE yecb_sheet_title,
+ TYPE ycl_ecb_template_data=>ts_template_data_sheet.
+
+
+ lo_template_filler = ycl_ecb_fill_template=>create( me ).
+
+ LOOP AT lo_template_filler->mt_sheet ASSIGNING .
+
+ READ TABLE iv_data->mt_data ASSIGNING WITH KEY sheet = .
+ CHECK sy-subrc = 0.
+ lo_template_filler->fill_sheet( ).
+
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+ METHOD get_active_sheet_index.
+ r_active_worksheet = me->worksheets->active_worksheet.
+ ENDMETHOD.
+
+
+ METHOD get_active_worksheet.
+
+ eo_worksheet = me->worksheets->get( me->worksheets->active_worksheet ).
+
+ ENDMETHOD.
+
+
+ METHOD get_autofilters_reference.
+
+ ro_autofilters = autofilters.
+
+ ENDMETHOD.
+
+
+ METHOD get_default_style.
+ ep_style = me->default_style.
+ ENDMETHOD.
+
+
+ METHOD get_drawings_iterator.
+
+ CASE ip_type.
+ WHEN ycl_ecb_drawing=>type_image.
+ eo_iterator = me->drawings->get_iterator( ).
+ WHEN ycl_ecb_drawing=>type_chart.
+ eo_iterator = me->charts->get_iterator( ).
+ WHEN OTHERS.
+ ENDCASE.
+
+ ENDMETHOD.
+
+
+ METHOD get_next_table_id.
+ DATA: lo_worksheet TYPE REF TO ycl_ecb_worksheet,
+ lo_iterator TYPE REF TO ycl_ecb_collection_iterator,
+ lv_tables_count TYPE i.
+
+ lo_iterator = me->get_worksheets_iterator( ).
+ WHILE lo_iterator->has_next( ) EQ abap_true.
+ lo_worksheet ?= lo_iterator->get_next( ).
+
+ lv_tables_count = lo_worksheet->get_tables_size( ).
+ ADD lv_tables_count TO ep_id.
+
+ ENDWHILE.
+
+ ADD 1 TO ep_id.
+
+ ENDMETHOD.
+
+
+ METHOD get_ranges_iterator.
+
+ eo_iterator = me->ranges->get_iterator( ).
+
+ ENDMETHOD.
+
+
+ METHOD get_static_cellstyle_guid.
+ " # issue 139
+ DATA: style LIKE LINE OF me->t_stylemapping1.
+
+ READ TABLE me->t_stylemapping1 INTO style
+ WITH TABLE KEY dynamic_style_guid = style-guid " no dynamic style --> look for initial guid here
+ complete_style = ip_cstyle_complete
+ complete_stylex = ip_cstylex_complete.
+ IF sy-subrc <> 0.
+ style-complete_style = ip_cstyle_complete.
+ style-complete_stylex = ip_cstylex_complete.
+ style-guid = ycl_ecb_obsolete_func_wrap=>guid_create( ). " ins issue #379 - replacement for outdated function call
+ INSERT style INTO TABLE me->t_stylemapping1.
+ INSERT style INTO TABLE me->t_stylemapping2.
+
+ ENDIF.
+
+ ep_guid = style-guid.
+ ENDMETHOD.
+
+
+ METHOD get_styles_iterator.
+
+ eo_iterator = me->styles->get_iterator( ).
+
+ ENDMETHOD.
+
+
+ METHOD get_style_from_guid.
+
+ DATA: lo_style TYPE REF TO ycl_ecb_style,
+ lo_iterator TYPE REF TO ycl_ecb_collection_iterator.
+
+ lo_iterator = styles->get_iterator( ).
+ WHILE lo_iterator->has_next( ) = abap_true.
+ lo_style ?= lo_iterator->get_next( ).
+ IF lo_style->get_guid( ) = ip_guid.
+ eo_style = lo_style.
+ RETURN.
+ ENDIF.
+ ENDWHILE.
+
+ ENDMETHOD.
+
+
+ METHOD get_style_index_in_styles.
+ DATA: index TYPE i.
+ DATA: lo_iterator TYPE REF TO ycl_ecb_collection_iterator,
+ lo_style TYPE REF TO ycl_ecb_style.
+
+ CHECK ip_guid IS NOT INITIAL.
+
+
+ lo_iterator = me->get_styles_iterator( ).
+ WHILE lo_iterator->has_next( ) = 'X'.
+ ADD 1 TO index.
+ lo_style ?= lo_iterator->get_next( ).
+ IF lo_style->get_guid( ) = ip_guid.
+ ep_index = index.
+ EXIT.
+ ENDIF.
+ ENDWHILE.
+
+ IF ep_index IS INITIAL.
+ ycx_ecb=>raise_text( 'Index not found' ).
+ ELSE.
+ SUBTRACT 1 FROM ep_index. " In excel list starts with "0"
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD get_style_to_guid.
+ DATA: lo_style TYPE REF TO ycl_ecb_style.
+ " # issue 139
+ READ TABLE me->t_stylemapping2 INTO ep_stylemapping WITH TABLE KEY guid = ip_guid.
+ IF sy-subrc <> 0.
+ ycx_ecb=>raise_text( 'GUID not found' ).
+ ENDIF.
+
+ IF ep_stylemapping-dynamic_style_guid IS NOT INITIAL.
+ lo_style = me->get_style_from_guid( ip_guid ).
+ ycl_ecb_common=>recursive_class_to_struct( EXPORTING i_source = lo_style
+ CHANGING e_target = ep_stylemapping-complete_style
+ e_targetx = ep_stylemapping-complete_stylex ).
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD get_theme.
+ eo_theme = theme.
+ ENDMETHOD.
+
+
+ METHOD get_worksheets_iterator.
+
+ eo_iterator = me->worksheets->get_iterator( ).
+
+ ENDMETHOD.
+
+
+ METHOD get_worksheets_name.
+
+ ep_name = me->worksheets->name.
+
+ ENDMETHOD.
+
+
+ METHOD get_worksheets_size.
+
+ ep_size = me->worksheets->size( ).
+
+ ENDMETHOD.
+
+
+ METHOD get_worksheet_by_index.
+
+
+ DATA: lv_index TYPE yecb_active_worksheet.
+
+ lv_index = iv_index.
+ eo_worksheet = me->worksheets->get( lv_index ).
+
+ ENDMETHOD.
+
+
+ METHOD get_worksheet_by_name.
+
+ DATA: lv_index TYPE yecb_active_worksheet,
+ l_size TYPE i.
+
+ l_size = get_worksheets_size( ).
+
+ DO l_size TIMES.
+ lv_index = sy-index.
+ eo_worksheet = me->worksheets->get( lv_index ).
+ IF eo_worksheet->get_title( ) = ip_sheet_name.
+ RETURN.
+ ENDIF.
+ ENDDO.
+
+ CLEAR eo_worksheet.
+
+ ENDMETHOD.
+
+
+ METHOD set_active_sheet_index.
+ DATA: lo_worksheet TYPE REF TO ycl_ecb_worksheet,
+ lv_errormessage TYPE string.
+
+*--------------------------------------------------------------------*
+* Check whether worksheet exists
+*--------------------------------------------------------------------*
+ lo_worksheet = me->get_worksheet_by_index( i_active_worksheet ).
+ IF lo_worksheet IS NOT BOUND.
+ lv_errormessage = 'Worksheet not existing'(001).
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDIF.
+
+ me->worksheets->active_worksheet = i_active_worksheet.
+
+ ENDMETHOD.
+
+
+ METHOD set_active_sheet_index_by_name.
+
+ DATA: ws_it TYPE REF TO ycl_ecb_collection_iterator,
+ ws TYPE REF TO ycl_ecb_worksheet,
+ lv_title TYPE yecb_sheet_title,
+ count TYPE i VALUE 1.
+
+ ws_it = me->worksheets->get_iterator( ).
+
+ WHILE ws_it->has_next( ) = abap_true.
+ ws ?= ws_it->get_next( ).
+ lv_title = ws->get_title( ).
+ IF lv_title = i_worksheet_name.
+ me->worksheets->active_worksheet = count.
+ EXIT.
+ ENDIF.
+ count = count + 1.
+ ENDWHILE.
+
+ ENDMETHOD.
+
+
+ METHOD set_default_style.
+ me->default_style = ip_style.
+ ENDMETHOD.
+
+
+ METHOD set_theme.
+ theme = io_theme.
+ ENDMETHOD.
+
+
+ METHOD stylemapping_dynamic_style.
+ " # issue 139
+ eo_style2-dynamic_style_guid = ip_style->get_guid( ).
+ eo_style2-guid = eo_style2-dynamic_style_guid.
+ eo_style2-added_to_iterator = abap_true.
+
+* don't care about attributes here, since this data may change
+* dynamically
+
+ ENDMETHOD.
+
+
+ METHOD yif_ecb_book_properties~initialize.
+ DATA: lv_timestamp TYPE timestampl.
+
+ me->yif_ecb_book_properties~application = 'Microsoft Excel'.
+ me->yif_ecb_book_properties~appversion = '12.0000'.
+
+ GET TIME STAMP FIELD lv_timestamp.
+ me->yif_ecb_book_properties~created = lv_timestamp.
+ me->yif_ecb_book_properties~creator = sy-uname.
+ me->yif_ecb_book_properties~description = ycl_ecb=>version.
+ me->yif_ecb_book_properties~modified = lv_timestamp.
+ me->yif_ecb_book_properties~lastmodifiedby = sy-uname.
+ ENDMETHOD.
+
+
+ METHOD yif_ecb_book_protection~initialize.
+ me->yif_ecb_book_protection~protected = yif_ecb_book_protection=>c_unprotected.
+ me->yif_ecb_book_protection~lockrevision = yif_ecb_book_protection=>c_unlocked.
+ me->yif_ecb_book_protection~lockstructure = yif_ecb_book_protection=>c_unlocked.
+ me->yif_ecb_book_protection~lockwindows = yif_ecb_book_protection=>c_unlocked.
+ CLEAR me->yif_ecb_book_protection~workbookpassword.
+ CLEAR me->yif_ecb_book_protection~revisionspassword.
+ ENDMETHOD.
+
+
+ METHOD yif_ecb_book_vba_project~set_codename.
+ me->yif_ecb_book_vba_project~codename = ip_codename.
+ ENDMETHOD.
+
+
+ METHOD yif_ecb_book_vba_project~set_codename_pr.
+ me->yif_ecb_book_vba_project~codename_pr = ip_codename_pr.
+ ENDMETHOD.
+
+
+ METHOD yif_ecb_book_vba_project~set_vbaproject.
+ me->yif_ecb_book_vba_project~vbaproject = ip_vbaproject.
+ ENDMETHOD.
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb.clas.testclasses.abap b/src/abap2xlsx/ycl_ecb.clas.testclasses.abap
new file mode 100644
index 0000000..a0c080e
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb.clas.testclasses.abap
@@ -0,0 +1,100 @@
+CLASS zcl_tc_excel DEFINITION DEFERRED.
+CLASS ycl_ecb DEFINITION LOCAL FRIENDS zcl_tc_excel.
+
+*----------------------------------------------------------------------*
+* CLASS zcl_Tc_Excel DEFINITION
+*----------------------------------------------------------------------*
+*
+*----------------------------------------------------------------------*
+CLASS zcl_tc_excel DEFINITION FOR TESTING
+ DURATION SHORT
+ RISK LEVEL HARMLESS
+.
+*?
+*?
+*?
+*?zcl_Tc_Excel
+*?
+*?f_Cut
+*?
+*?ZCL_EXCEL
+*?
+*?
+*?X
+*?
+*?X
+*?
+*?X
+*?
+*?X
+*?
+*?
+*?
+*?
+ PRIVATE SECTION.
+* ================
+ DATA:
+ f_cut TYPE REF TO ycl_ecb. "class under test
+
+ CLASS-METHODS: class_setup.
+ CLASS-METHODS: class_teardown.
+ METHODS: setup.
+ METHODS: teardown.
+ METHODS: create_empty_excel FOR TESTING.
+
+ENDCLASS. "zcl_Tc_Excel
+
+
+*----------------------------------------------------------------------*
+* CLASS zcl_Tc_Excel IMPLEMENTATION
+*----------------------------------------------------------------------*
+*
+*----------------------------------------------------------------------*
+CLASS zcl_tc_excel IMPLEMENTATION.
+* ==================================
+
+ METHOD class_setup.
+* ===================
+
+
+ ENDMETHOD. "class_Setup
+
+
+ METHOD class_teardown.
+* ======================
+
+
+ ENDMETHOD. "class_Teardown
+
+
+ METHOD setup.
+* =============
+
+ CREATE OBJECT f_cut.
+ ENDMETHOD. "setup
+
+
+ METHOD teardown.
+* ================
+
+
+ ENDMETHOD. "teardown
+
+*// START TEST METHODS
+
+ METHOD create_empty_excel.
+* ==================================
+
+ DATA: lv_count TYPE i.
+ lv_count = f_cut->get_worksheets_size( ).
+
+ cl_abap_unit_assert=>assert_equals( act = lv_count
+ exp = 1
+ msg = 'Testing number of sheet'
+ level = if_aunit_constants=>tolerable ).
+ ENDMETHOD. "create_empty_excel
+
+*// END TEST METHODS
+
+
+ENDCLASS. "zcl_Tc_Excel
diff --git a/src/abap2xlsx/ycl_ecb.clas.xml b/src/abap2xlsx/ycl_ecb.clas.xml
new file mode 100644
index 0000000..7054e31
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb.clas.xml
@@ -0,0 +1,448 @@
+
+
+
+
+
+ YCL_ECB
+ E
+ Excel creator
+ 1
+ X
+ X
+ X
+ X
+
+
+ -
+ I
+ 001
+ Worksheet not existing
+ 30
+
+ -
+ I
+ 002
+ Deleting last remaining worksheet is not allowed
+ 60
+
+
+
+
+ ADD_NEW_AUTOFILTER
+ E
+ Create a new autofilter
+
+
+ ADD_NEW_AUTOFILTER
+ I
+ Create a new autofilter
+
+
+ ADD_NEW_DRAWING
+ E
+ Create a new drawing
+
+
+ ADD_NEW_DRAWING
+ I
+ Create a new drawing
+
+
+ ADD_NEW_RANGE
+ E
+ Create a new range
+
+
+ ADD_NEW_RANGE
+ I
+ Create a new range
+
+
+ ADD_NEW_STYLE
+ E
+ Create a new style
+
+
+ ADD_NEW_STYLE
+ I
+ Create a new style
+
+
+ ADD_NEW_WORKSHEET
+ E
+ Create a new worksheet
+
+
+ ADD_NEW_WORKSHEET
+ I
+ Create a new worksheet
+
+
+ ADD_STATIC_STYLES
+ E
+ Add static styles to styles iterator
+
+
+ ADD_STATIC_STYLES
+ I
+ Add static styles to styles iterator
+
+
+ AUTOFILTERS
+ E
+ Autofilters collection
+
+
+ AUTOFILTERS
+ I
+ Autofilters collection
+
+
+ CHARTS
+ E
+ Charts collection
+
+
+ CHARTS
+ I
+ Charts collection
+
+
+ CONSTRUCTOR
+ E
+ CONSTRUCTOR
+
+
+ CONSTRUCTOR
+ I
+ CONSTRUCTOR
+
+
+ DEFAULT_STYLE
+ E
+ Style identifier
+
+
+ DEFAULT_STYLE
+ I
+ Style identifier
+
+
+ DELETE_WORKSHEET
+ E
+ Delete worksheet
+
+
+ DELETE_WORKSHEET_BY_INDEX
+ E
+ Delete worksheet by index
+
+
+ DELETE_WORKSHEET_BY_NAME
+ E
+ Delete worksheet by name
+
+
+ DRAWINGS
+ E
+ Drawings collection
+
+
+ DRAWINGS
+ I
+ Worksheets collection
+
+
+ GET_ACTIVE_SHEET_INDEX
+ E
+ Get active worksheet index
+
+
+ GET_ACTIVE_SHEET_INDEX
+ I
+ Get active worksheet index
+
+
+ GET_ACTIVE_WORKSHEET
+ E
+ Get active worksheet
+
+
+ GET_ACTIVE_WORKSHEET
+ I
+ Get active worksheet
+
+
+ GET_AUTOFILTERS_REFERENCE
+ E
+ Get filter reference
+
+
+ GET_AUTOFILTERS_REFERENCE
+ I
+ Get filter reference
+
+
+ GET_DEFAULT_STYLE
+ E
+ Get default style
+
+
+ GET_DEFAULT_STYLE
+ I
+ Get default style
+
+
+ GET_DRAWINGS_ITERATOR
+ E
+ Get drawing iterator
+
+
+ GET_DRAWINGS_ITERATOR
+ I
+ Get drawing iterator
+
+
+ GET_NEXT_TABLE_ID
+ E
+ Get table ID unique across sheets
+
+
+ GET_NEXT_TABLE_ID
+ I
+ Get table ID unique across sheets
+
+
+ GET_RANGES_ITERATOR
+ E
+ Get ranges iterator
+
+
+ GET_RANGES_ITERATOR
+ I
+ Get ranges iterator
+
+
+ GET_STATIC_CELLSTYLE_GUID
+ E
+ Get GUID for static cellstyle
+
+
+ GET_STATIC_CELLSTYLE_GUID
+ I
+ Get GUID for static cellstyle
+
+
+ GET_STYLES_ITERATOR
+ E
+ Get styles iterator
+
+
+ GET_STYLES_ITERATOR
+ I
+ Get styles iterator
+
+
+ GET_STYLE_FROM_GUID
+ E
+ Return a style object from a GUID
+
+
+ GET_STYLE_INDEX_IN_STYLES
+ E
+ Get index of style in styles
+
+
+ GET_STYLE_INDEX_IN_STYLES
+ I
+ Get index of style in styles
+
+
+ GET_STYLE_TO_GUID
+ E
+ Get style(structure) for guid
+
+
+ GET_STYLE_TO_GUID
+ I
+ Get style(structure) for guid
+
+
+ GET_THEME
+ E
+ Gets theme
+
+
+ GET_WORKSHEETS_ITERATOR
+ E
+ Get worksheets iterator
+
+
+ GET_WORKSHEETS_ITERATOR
+ I
+ Get worksheets iterator
+
+
+ GET_WORKSHEETS_NAME
+ E
+ Returns the name of worksheets
+
+
+ GET_WORKSHEETS_NAME
+ I
+ Returns the name of worksheets
+
+
+ GET_WORKSHEETS_SIZE
+ E
+ Returns the number of worksheets
+
+
+ GET_WORKSHEETS_SIZE
+ I
+ Returns the number of worksheets
+
+
+ GET_WORKSHEET_BY_INDEX
+ E
+ Get worksheet by index
+
+
+ GET_WORKSHEET_BY_NAME
+ E
+ Get worksheet by name
+
+
+ GET_WORKSHEET_BY_NAME
+ I
+ Get worksheet by name
+
+
+ RANGES
+ E
+ Ranges collection
+
+
+ RANGES
+ I
+ Ranges collection
+
+
+ SECURITY
+ E
+ Security
+
+
+ SECURITY
+ I
+ Security
+
+
+ SET_ACTIVE_SHEET_INDEX
+ E
+ Set active worksheet index
+
+
+ SET_ACTIVE_SHEET_INDEX
+ I
+ Set active worksheet index
+
+
+ SET_ACTIVE_SHEET_INDEX_BY_NAME
+ E
+ Set active worksheet index by name
+
+
+ SET_ACTIVE_SHEET_INDEX_BY_NAME
+ I
+ Set active worksheet index by name
+
+
+ SET_DEFAULT_STYLE
+ E
+ Set default style
+
+
+ SET_DEFAULT_STYLE
+ I
+ Set default style
+
+
+ SET_THEME
+ E
+ Sets theme
+
+
+ STYLEMAPPING_DYNAMIC_STYLE
+ E
+ Convert dynamic style to static styleentry
+
+
+ STYLEMAPPING_DYNAMIC_STYLE
+ I
+ Convert dynamic style to static stlyeentry
+
+
+ STYLES
+ E
+ Styles collection
+
+
+ STYLES
+ I
+ Styles collection
+
+
+ THEME
+ E
+ Theme
+
+
+ T_STYLEMAPPING1
+ E
+ Stylemapping: Values -> GUID
+
+
+ T_STYLEMAPPING1
+ I
+ Stylemapping: Values -> GUID
+
+
+ T_STYLEMAPPING2
+ E
+ Stylemapping: GUID -> Values
+
+
+ T_STYLEMAPPING2
+ I
+ Stylemapping: GUID -> Values
+
+
+ USE_TEMPLATE
+ E
+ Checkbox
+
+
+ USE_TEMPLATE
+ I
+ Checkbox
+
+
+ VERSION
+ E
+ abap2xlsx version
+
+
+ WORKSHEETS
+ E
+ Worksheets collection
+
+
+ WORKSHEETS
+ I
+ Worksheets collection
+
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb_autofilter.clas.abap b/src/abap2xlsx/ycl_ecb_autofilter.clas.abap
new file mode 100644
index 0000000..b23837c
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_autofilter.clas.abap
@@ -0,0 +1,440 @@
+CLASS ycl_ecb_autofilter DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+*"* public components of class ZCL_EXCEL_AUTOFILTER
+*"* do not include other source files here!!!
+ PUBLIC SECTION.
+
+ TYPES tv_filter_rule TYPE string .
+ TYPES tv_logical_operator TYPE c LENGTH 3 .
+ TYPES:
+ BEGIN OF ts_filter,
+ column TYPE yecb_cell_column,
+ rule TYPE tv_filter_rule,
+ t_values TYPE HASHED TABLE OF yecb_cell_value WITH UNIQUE KEY table_line,
+ tr_textfilter1 TYPE RANGE OF string,
+ logical_operator TYPE tv_logical_operator,
+ tr_textfilter2 TYPE RANGE OF string,
+ END OF ts_filter .
+ TYPES:
+ tt_filters TYPE HASHED TABLE OF ts_filter WITH UNIQUE KEY column .
+
+ DATA filter_area TYPE yecb_s_autofilter_area .
+ CONSTANTS mc_filter_rule_single_values TYPE tv_filter_rule VALUE 'single_values'. "#EC NOTEXT
+ CONSTANTS mc_filter_rule_text_pattern TYPE tv_filter_rule VALUE 'text_pattern'. "#EC NOTEXT
+ CONSTANTS mc_logical_operator_and TYPE tv_logical_operator VALUE 'and'. "#EC NOTEXT
+ CONSTANTS mc_logical_operator_none TYPE tv_logical_operator VALUE space. "#EC NOTEXT
+ CONSTANTS mc_logical_operator_or TYPE tv_logical_operator VALUE 'or'. "#EC NOTEXT
+
+ METHODS constructor
+ IMPORTING
+ !io_sheet TYPE REF TO ycl_ecb_worksheet .
+ METHODS get_filter_area
+ RETURNING
+ VALUE(rs_area) TYPE yecb_s_autofilter_area
+ RAISING
+ ycx_ecb .
+ METHODS get_filter_range
+ RETURNING
+ VALUE(r_range) TYPE yecb_cell_value
+ RAISING
+ ycx_ecb.
+ METHODS get_filter_reference
+ RETURNING
+ VALUE(r_ref) TYPE yecb_range_value
+ RAISING
+ ycx_ecb .
+ METHODS get_values
+ RETURNING
+ VALUE(rt_filter) TYPE yecb_t_autofilter_values .
+ METHODS is_row_hidden
+ IMPORTING
+ !iv_row TYPE yecb_cell_row
+ RETURNING
+ VALUE(rv_is_hidden) TYPE abap_bool .
+ METHODS set_filter_area
+ IMPORTING
+ !is_area TYPE yecb_s_autofilter_area .
+ METHODS set_text_filter
+ IMPORTING
+ !i_column TYPE yecb_cell_column
+ !iv_textfilter1 TYPE clike
+ !iv_logical_operator TYPE tv_logical_operator DEFAULT mc_logical_operator_none
+ !iv_textfilter2 TYPE clike OPTIONAL .
+ METHODS set_value
+ IMPORTING
+ !i_column TYPE yecb_cell_column
+ !i_value TYPE yecb_cell_value .
+ METHODS set_values
+ IMPORTING
+ !it_values TYPE yecb_t_autofilter_values .
+*"* protected components of class ZABAP_EXCEL_WORKSHEET
+*"* do not include other source files here!!!
+ PROTECTED SECTION.
+
+ METHODS get_column_filter
+ IMPORTING
+ !i_column TYPE yecb_cell_column
+ RETURNING
+ VALUE(rr_filter) TYPE REF TO ts_filter .
+ METHODS is_row_hidden_single_values
+ IMPORTING
+ !iv_row TYPE yecb_cell_row
+ !iv_col TYPE yecb_cell_column
+ !is_filter TYPE ts_filter
+ RETURNING
+ VALUE(rv_is_hidden) TYPE abap_bool .
+ METHODS is_row_hidden_text_pattern
+ IMPORTING
+ !iv_row TYPE yecb_cell_row
+ !iv_col TYPE yecb_cell_column
+ !is_filter TYPE ts_filter
+ RETURNING
+ VALUE(rv_is_hidden) TYPE abap_bool .
+*"* private components of class ZCL_EXCEL_AUTOFILTER
+*"* do not include other source files here!!!
+ PRIVATE SECTION.
+
+ DATA worksheet TYPE REF TO ycl_ecb_worksheet .
+ DATA mt_filters TYPE tt_filters .
+
+ METHODS validate_area
+ RAISING
+ ycx_ecb .
+ENDCLASS.
+
+
+
+CLASS ycl_ecb_autofilter IMPLEMENTATION.
+
+
+ METHOD constructor.
+ worksheet = io_sheet.
+ ENDMETHOD.
+
+
+ METHOD get_column_filter.
+
+ DATA: ls_filter LIKE LINE OF me->mt_filters.
+
+ READ TABLE me->mt_filters REFERENCE INTO rr_filter WITH TABLE KEY column = i_column.
+ IF sy-subrc <> 0.
+ ls_filter-column = i_column.
+ INSERT ls_filter INTO TABLE me->mt_filters REFERENCE INTO rr_filter.
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD get_filter_area.
+
+ validate_area( ).
+
+ rs_area = filter_area.
+
+ ENDMETHOD.
+
+
+ METHOD get_filter_range.
+ DATA: l_row_start_c TYPE string,
+ l_row_end_c TYPE string,
+ l_col_start_c TYPE string,
+ l_col_end_c TYPE string.
+
+ validate_area( ).
+
+ l_row_end_c = filter_area-row_end.
+ CONDENSE l_row_end_c NO-GAPS.
+
+ l_row_start_c = filter_area-row_start.
+ CONDENSE l_row_start_c NO-GAPS.
+
+ l_col_start_c = ycl_ecb_common=>convert_column2alpha( ip_column = filter_area-col_start ) .
+ l_col_end_c = ycl_ecb_common=>convert_column2alpha( ip_column = filter_area-col_end ) .
+
+ CONCATENATE l_col_start_c l_row_start_c ':' l_col_end_c l_row_end_c INTO r_range.
+
+ ENDMETHOD.
+
+
+ METHOD get_filter_reference.
+ DATA: l_row_start_c TYPE string,
+ l_row_end_c TYPE string,
+ l_col_start_c TYPE string,
+ l_col_end_c TYPE string,
+ l_value TYPE string.
+
+ validate_area( ).
+
+ l_row_end_c = filter_area-row_end.
+ CONDENSE l_row_end_c NO-GAPS.
+
+ l_row_start_c = filter_area-row_start.
+ CONDENSE l_row_start_c NO-GAPS.
+
+ l_col_start_c = ycl_ecb_common=>convert_column2alpha( ip_column = filter_area-col_start ) .
+ l_col_end_c = ycl_ecb_common=>convert_column2alpha( ip_column = filter_area-col_end ) .
+ l_value = worksheet->get_title( ) .
+
+ r_ref = ycl_ecb_common=>escape_string( ip_value = l_value ).
+
+ CONCATENATE r_ref '!$' l_col_start_c '$' l_row_start_c ':$' l_col_end_c '$' l_row_end_c INTO r_ref.
+
+ ENDMETHOD.
+
+
+ METHOD get_values.
+
+ FIELD-SYMBOLS: LIKE LINE OF me->mt_filters,
+ LIKE LINE OF -t_values.
+
+ DATA: ls_filter LIKE LINE OF rt_filter.
+
+ LOOP AT me->mt_filters ASSIGNING WHERE rule = mc_filter_rule_single_values.
+
+ ls_filter-column = -column.
+ LOOP AT -t_values ASSIGNING .
+ ls_filter-value = .
+ APPEND ls_filter TO rt_filter.
+ ENDLOOP.
+
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+ METHOD is_row_hidden.
+
+
+ DATA: lr_filter TYPE REF TO ts_filter,
+ lv_col TYPE i.
+
+ FIELD-SYMBOLS: TYPE ts_filter.
+
+ rv_is_hidden = abap_false.
+
+*--------------------------------------------------------------------*
+* 1st row of filter area is never hidden, because here the filter
+* symbol is being shown
+*--------------------------------------------------------------------*
+ IF iv_row = me->filter_area-row_start.
+ RETURN.
+ ENDIF.
+
+
+ lv_col = me->filter_area-col_start.
+
+
+ WHILE lv_col <= me->filter_area-col_end.
+
+ lr_filter = me->get_column_filter( lv_col ).
+ ASSIGN lr_filter->* TO .
+
+ CASE -rule.
+
+ WHEN mc_filter_rule_single_values.
+ rv_is_hidden = me->is_row_hidden_single_values( iv_row = iv_row
+ iv_col = lv_col
+ is_filter = ).
+
+ WHEN mc_filter_rule_text_pattern.
+ rv_is_hidden = me->is_row_hidden_text_pattern( iv_row = iv_row
+ iv_col = lv_col
+ is_filter = ).
+
+ ENDCASE.
+
+ IF rv_is_hidden = abap_true.
+ RETURN.
+ ENDIF.
+
+
+ ADD 1 TO lv_col.
+
+ ENDWHILE.
+
+
+ ENDMETHOD.
+
+
+ METHOD is_row_hidden_single_values.
+
+
+ DATA: lv_value TYPE string.
+
+ FIELD-SYMBOLS: LIKE LINE OF me->worksheet->sheet_content.
+
+ rv_is_hidden = abap_false. " Default setting is NOT HIDDEN = is in filter range
+
+*--------------------------------------------------------------------*
+* No filter values --> only symbol should be shown but nothing is being hidden
+*--------------------------------------------------------------------*
+ IF is_filter-t_values IS INITIAL.
+ RETURN.
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Get value of cell
+*--------------------------------------------------------------------*
+ READ TABLE me->worksheet->sheet_content ASSIGNING WITH TABLE KEY cell_row = iv_row
+ cell_column = iv_col.
+ IF sy-subrc = 0.
+ lv_value = -cell_value.
+ ELSE.
+ CLEAR lv_value.
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Check whether it is affected by filter
+* this needs to be extended if we support other filtertypes
+* other than single values
+*--------------------------------------------------------------------*
+ READ TABLE is_filter-t_values TRANSPORTING NO FIELDS WITH TABLE KEY table_line = lv_value.
+ IF sy-subrc <> 0.
+ rv_is_hidden = abap_true.
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD is_row_hidden_text_pattern.
+
+
+
+ DATA: lv_value TYPE string.
+
+ FIELD-SYMBOLS: LIKE LINE OF me->worksheet->sheet_content.
+
+ rv_is_hidden = abap_false. " Default setting is NOT HIDDEN = is in filter range
+
+*--------------------------------------------------------------------*
+* Get value of cell
+*--------------------------------------------------------------------*
+ READ TABLE me->worksheet->sheet_content ASSIGNING WITH TABLE KEY cell_row = iv_row
+ cell_column = iv_col.
+ IF sy-subrc = 0.
+ lv_value = -cell_value.
+ ELSE.
+ CLEAR lv_value.
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Check whether it is affected by filter
+* this needs to be extended if we support other filtertypes
+* other than single values
+*--------------------------------------------------------------------*
+ IF lv_value NOT IN is_filter-tr_textfilter1.
+ rv_is_hidden = abap_true.
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD set_filter_area.
+
+ filter_area = is_area.
+
+ ENDMETHOD.
+
+
+ METHOD set_text_filter.
+* see method documentation how to use this
+
+ DATA: lr_filter TYPE REF TO ts_filter,
+ ls_value1 TYPE LINE OF ts_filter-tr_textfilter1.
+
+ FIELD-SYMBOLS: TYPE ts_filter.
+
+
+ lr_filter = me->get_column_filter( i_column ).
+ ASSIGN lr_filter->* TO .
+
+ -rule = mc_filter_rule_text_pattern.
+ CLEAR -tr_textfilter1.
+
+ IF iv_textfilter1 CA '*+'. " Pattern
+ ls_value1-sign = 'I'.
+ ls_value1-option = 'CP'.
+ ls_value1-low = iv_textfilter1.
+ ELSE.
+ ls_value1-sign = 'I'.
+ ls_value1-option = 'EQ'.
+ ls_value1-low = iv_textfilter1.
+ ENDIF.
+ APPEND ls_value1 TO -tr_textfilter1.
+
+ ENDMETHOD.
+
+
+ METHOD set_value.
+
+ DATA: lr_filter TYPE REF TO ts_filter.
+
+ FIELD-SYMBOLS: TYPE ts_filter.
+
+
+ lr_filter = me->get_column_filter( i_column ).
+ ASSIGN lr_filter->* TO .
+
+ -rule = mc_filter_rule_single_values.
+
+ INSERT i_value INTO TABLE -t_values.
+
+ ENDMETHOD.
+
+
+ METHOD set_values.
+
+ FIELD-SYMBOLS: LIKE LINE OF it_values.
+
+ LOOP AT it_values ASSIGNING .
+
+ me->set_value( i_column = -column
+ i_value = -value ).
+
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+ METHOD validate_area.
+ DATA: l_col TYPE yecb_cell_column,
+ ls_original_filter_area TYPE yecb_s_autofilter_area,
+ l_row TYPE yecb_cell_row.
+
+ l_row = worksheet->get_highest_row( ) .
+ l_col = worksheet->get_highest_column( ) .
+
+ IF filter_area IS INITIAL.
+ filter_area-row_start = 1.
+ filter_area-col_start = 1.
+ filter_area-row_end = l_row .
+ filter_area-col_end = l_col .
+ ENDIF.
+
+ IF filter_area-row_start > filter_area-row_end.
+ ls_original_filter_area = filter_area.
+ filter_area-row_start = ls_original_filter_area-row_end.
+ filter_area-row_end = ls_original_filter_area-row_start.
+ ENDIF.
+ IF filter_area-row_start < 1.
+ filter_area-row_start = 1.
+ ENDIF.
+ IF filter_area-col_start < 1.
+ filter_area-col_start = 1.
+ ENDIF.
+ IF filter_area-row_end > l_row OR
+ filter_area-row_end < 1.
+ filter_area-row_end = l_row.
+ ENDIF.
+ IF filter_area-col_end > l_col OR
+ filter_area-col_end < 1.
+ filter_area-col_end = l_col.
+ ENDIF.
+ IF filter_area-col_start > filter_area-col_end.
+ filter_area-col_start = filter_area-col_end.
+ ENDIF.
+ ENDMETHOD.
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_autofilter.clas.xml b/src/abap2xlsx/ycl_ecb_autofilter.clas.xml
new file mode 100644
index 0000000..459ac48
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_autofilter.clas.xml
@@ -0,0 +1,203 @@
+
+
+
+
+
+ YCL_ECB_AUTOFILTER
+ E
+ Autofilter
+ 1
+ X
+ X
+ X
+
+
+
+ CONSTRUCTOR
+ E
+ CONSTRUCTOR
+
+
+ CONSTRUCTOR
+ I
+ CONSTRUCTOR
+
+
+ FILTER_AREA
+ E
+ Autofilter area ( rows and columns )
+
+
+ FILTER_AREA
+ I
+ Autofilter area ( rows and columns )
+
+
+ GET_COLUMN_FILTER
+ E
+ Get filter for column
+
+
+ GET_FILTER_AREA
+ E
+ Get filter area for filter
+
+
+ GET_FILTER_AREA
+ I
+ Get filter area for filter
+
+
+ GET_FILTER_RANGE
+ E
+ Get Filter range for filter
+
+
+ GET_FILTER_RANGE
+ I
+ Get Filter range for filter
+
+
+ GET_FILTER_REFERENCE
+ E
+ Get filter reference for filter
+
+
+ GET_FILTER_REFERENCE
+ I
+ Get filter reference for filter
+
+
+ GET_VALUES
+ E
+ Get filter values table
+
+
+ GET_VALUES
+ I
+ Get filter values table
+
+
+ IS_ROW_HIDDEN
+ E
+ Is cellrow hidden by this autofilter
+
+
+ IS_ROW_HIDDEN_SINGLE_VALUES
+ E
+ Is cellrow hidden by this autofilter if rule single values
+
+
+ IS_ROW_HIDDEN_TEXT_PATTERN
+ E
+ Is cellrow hidden by this autofilter if rule text pattern
+
+
+ MC_FILTER_RULE_SINGLE_VALUES
+ E
+ Standard filter for single values
+
+
+ MC_FILTER_RULE_TEXT_PATTERN
+ E
+ Standard filter for single values
+
+
+ MC_LOGICAL_OPERATOR_AND
+ E
+ logical operator to be used in set_xxxxx_pattern
+
+
+ MC_LOGICAL_OPERATOR_NONE
+ E
+ logical operator to be used in set_xxxxx_pattern
+
+
+ MC_LOGICAL_OPERATOR_OR
+ E
+ logical operator to be used in set_xxxxx_pattern
+
+
+ MT_FILTERS
+ E
+ All textfilters
+
+
+ SET_FILTER_AREA
+ E
+ Set filter area for filter
+
+
+ SET_FILTER_AREA
+ I
+ Set filter area for filter
+
+
+ SET_TEXT_FILTER
+ E
+ Set filter by text pattern - see method documentation
+
+
+ SET_VALUE
+ E
+ Set Filter value
+
+
+ SET_VALUE
+ I
+ Set Filter value
+
+
+ SET_VALUES
+ E
+ Set Filter values with table
+
+
+ SET_VALUES
+ I
+ Set Filter values with table
+
+
+ TS_FILTER
+ E
+ Filter
+
+
+ TT_FILTERS
+ E
+ All filters
+
+
+ TV_FILTER_RULE
+ E
+ Filter rule
+
+
+ TV_LOGICAL_OPERATOR
+ E
+ logical operator to be used in set_xxxxx_pattern
+
+
+ VALIDATE_AREA
+ E
+ Validates filter area
+
+
+ VALIDATE_AREA
+ I
+ Validates filter area
+
+
+ WORKSHEET
+ E
+ Worksheet
+
+
+ WORKSHEET
+ I
+ Worksheet
+
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb_autofilters.clas.abap b/src/abap2xlsx/ycl_ecb_autofilters.clas.abap
new file mode 100644
index 0000000..6e1eada
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_autofilters.clas.abap
@@ -0,0 +1,120 @@
+CLASS ycl_ecb_autofilters DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+*"* public components of class ZCL_EXCEL_AUTOFILTERS
+*"* do not include other source files here!!!
+
+ CONSTANTS c_autofilter TYPE string VALUE '_xlnm._FilterDatabase'. "#EC NOTEXT
+
+ METHODS add
+ IMPORTING
+ !io_sheet TYPE REF TO ycl_ecb_worksheet
+ RETURNING
+ VALUE(ro_autofilter) TYPE REF TO ycl_ecb_autofilter
+ RAISING
+ ycx_ecb .
+ METHODS clear .
+ METHODS get
+ IMPORTING
+ !io_worksheet TYPE REF TO ycl_ecb_worksheet
+ RETURNING
+ VALUE(ro_autofilter) TYPE REF TO ycl_ecb_autofilter .
+ METHODS is_empty
+ RETURNING
+ VALUE(r_empty) TYPE flag .
+ METHODS remove
+ IMPORTING
+ !io_sheet TYPE any .
+ METHODS size
+ RETURNING
+ VALUE(r_size) TYPE i .
+*"* protected components of class ZABAP_EXCEL_WORKSHEETS
+*"* do not include other source files here!!!
+*"* protected components of class ZABAP_EXCEL_WORKSHEETS
+*"* do not include other source files here!!!
+ PROTECTED SECTION.
+ PRIVATE SECTION.
+
+ TYPES:
+ BEGIN OF ts_autofilter,
+ worksheet TYPE REF TO ycl_ecb_worksheet,
+ autofilter TYPE REF TO ycl_ecb_autofilter,
+ END OF ts_autofilter .
+ TYPES:
+ tt_autofilters TYPE HASHED TABLE OF ts_autofilter WITH UNIQUE KEY worksheet .
+
+ DATA mt_autofilters TYPE tt_autofilters .
+ENDCLASS.
+
+
+
+CLASS ycl_ecb_autofilters IMPLEMENTATION.
+
+
+ METHOD add.
+
+ DATA: ls_autofilter LIKE LINE OF me->mt_autofilters.
+
+ FIELD-SYMBOLS: LIKE LINE OF me->mt_autofilters.
+
+ READ TABLE me->mt_autofilters ASSIGNING WITH TABLE KEY worksheet = io_sheet.
+ IF sy-subrc = 0.
+ RAISE EXCEPTION TYPE ycx_ecb. " adding another autofilter to sheet is not allowed
+ ENDIF.
+
+ CREATE OBJECT ro_autofilter
+ EXPORTING
+ io_sheet = io_sheet.
+
+ ls_autofilter-worksheet = io_sheet.
+ ls_autofilter-autofilter = ro_autofilter.
+ INSERT ls_autofilter INTO TABLE me->mt_autofilters.
+
+
+ ENDMETHOD.
+
+
+ METHOD clear.
+
+ CLEAR me->mt_autofilters.
+
+ ENDMETHOD.
+
+
+ METHOD get.
+
+ FIELD-SYMBOLS: LIKE LINE OF me->mt_autofilters.
+
+ READ TABLE me->mt_autofilters ASSIGNING WITH TABLE KEY worksheet = io_worksheet.
+ IF sy-subrc = 0.
+ ro_autofilter = -autofilter.
+ ELSE.
+ CLEAR ro_autofilter.
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD is_empty.
+ IF me->mt_autofilters IS INITIAL.
+ r_empty = abap_true.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD remove.
+
+ DATA: lo_worksheet TYPE REF TO ycl_ecb_worksheet.
+
+ DELETE TABLE me->mt_autofilters WITH TABLE KEY worksheet = lo_worksheet.
+
+ ENDMETHOD.
+
+
+ METHOD size.
+ DESCRIBE TABLE me->mt_autofilters LINES r_size.
+ ENDMETHOD.
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_autofilters.clas.xml b/src/abap2xlsx/ycl_ecb_autofilters.clas.xml
new file mode 100644
index 0000000..dedf5d9
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_autofilters.clas.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+ YCL_ECB_AUTOFILTERS
+ E
+ Autofilters collection
+ 1
+ X
+ X
+ X
+
+
+
+ ADD
+ E
+ Adds an Element to the Collection
+
+
+ ADD
+ I
+ Adds an Element to the Collection
+
+
+ CLEAR
+ E
+ Initializes the Collection
+
+
+ CLEAR
+ I
+ Initializes the Collection
+
+
+ C_AUTOFILTER
+ E
+ Excel Autofilter range name
+
+
+ C_AUTOFILTER
+ I
+ Excel Autofilter range name
+
+
+ GET
+ E
+ Gets Element
+
+
+ GET
+ I
+ Gets Element
+
+
+ IS_EMPTY
+ E
+ Checks whether elements are contained
+
+
+ IS_EMPTY
+ I
+ Checks whether elements are contained
+
+
+ MT_AUTOFILTERS
+ E
+ All autofilters
+
+
+ REMOVE
+ E
+ Deletes an Element from the Collection
+
+
+ REMOVE
+ I
+ Deletes an Element from the Collection
+
+
+ SIZE
+ E
+ Specifies number of contained elements
+
+
+ SIZE
+ I
+ Specifies number of contained elements
+
+
+ TS_AUTOFILTER
+ E
+ Autofilter
+
+
+ TT_AUTOFILTERS
+ E
+ All autofilters
+
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb_collection.clas.abap b/src/abap2xlsx/ycl_ecb_collection.clas.abap
new file mode 100644
index 0000000..8424617
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_collection.clas.abap
@@ -0,0 +1,84 @@
+CLASS ycl_ecb_collection DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+
+ TYPES:
+ ty_collection TYPE STANDARD TABLE OF REF TO object .
+
+ DATA collection TYPE ty_collection READ-ONLY .
+
+ METHODS size
+ RETURNING
+ VALUE(size) TYPE i .
+ METHODS is_empty
+ RETURNING
+ VALUE(is_empty) TYPE abap_bool .
+ METHODS get
+ IMPORTING
+ !index TYPE i
+ RETURNING
+ VALUE(object) TYPE REF TO object .
+ METHODS get_iterator
+ RETURNING
+ VALUE(iterator) TYPE REF TO ycl_ecb_collection_iterator .
+ METHODS add
+ IMPORTING
+ !element TYPE REF TO object .
+ METHODS remove
+ IMPORTING
+ !element TYPE REF TO object .
+ METHODS clear .
+ PROTECTED SECTION.
+ PRIVATE SECTION.
+ENDCLASS.
+
+
+
+CLASS ycl_ecb_collection IMPLEMENTATION.
+
+
+ METHOD add .
+ APPEND element TO collection.
+ ENDMETHOD.
+
+
+ METHOD clear .
+ CLEAR collection.
+ ENDMETHOD.
+
+
+ METHOD get .
+ READ TABLE collection INDEX index INTO object.
+ ENDMETHOD.
+
+
+ METHOD get_iterator .
+ CREATE OBJECT iterator
+ EXPORTING
+ collection = me.
+ ENDMETHOD.
+
+
+ METHOD is_empty.
+ is_empty = boolc( size( ) = 0 ).
+ ENDMETHOD.
+
+
+ METHOD remove .
+ DATA obj TYPE REF TO object.
+ LOOP AT collection INTO obj.
+ IF obj = element.
+ DELETE collection.
+ RETURN.
+ ENDIF.
+ ENDLOOP.
+ ENDMETHOD.
+
+
+ METHOD size.
+ size = lines( collection ).
+ ENDMETHOD.
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_collection.clas.testclasses.abap b/src/abap2xlsx/ycl_ecb_collection.clas.testclasses.abap
new file mode 100644
index 0000000..90ff9b2
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_collection.clas.testclasses.abap
@@ -0,0 +1,37 @@
+CLASS ltcl_test DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS FINAL.
+
+ PRIVATE SECTION.
+ METHODS test01 FOR TESTING RAISING cx_static_check.
+ENDCLASS.
+
+
+CLASS ltcl_test IMPLEMENTATION.
+
+ METHOD test01.
+
+ DATA lo_collection TYPE REF TO ycl_ecb_collection.
+
+ CREATE OBJECT lo_collection.
+
+ cl_abap_unit_assert=>assert_equals(
+ act = lo_collection->size( )
+ exp = 0 ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = lo_collection->is_empty( )
+ exp = abap_true ).
+
+* heh, yea, add the collection to itself :)
+ lo_collection->add( lo_collection ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = lo_collection->size( )
+ exp = 1 ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = lo_collection->is_empty( )
+ exp = abap_false ).
+
+ ENDMETHOD.
+
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_collection.clas.xml b/src/abap2xlsx/ycl_ecb_collection.clas.xml
new file mode 100644
index 0000000..3419877
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_collection.clas.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ YCL_ECB_COLLECTION
+ E
+ abap2xlsx - Object Collection
+ 1
+ X
+ X
+ X
+ X
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb_collection_iterator.clas.abap b/src/abap2xlsx/ycl_ecb_collection_iterator.clas.abap
new file mode 100644
index 0000000..5af3fed
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_collection_iterator.clas.abap
@@ -0,0 +1,52 @@
+CLASS ycl_ecb_collection_iterator DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+ METHODS get_index
+ RETURNING
+ VALUE(index) TYPE i.
+ METHODS has_next
+ RETURNING
+ VALUE(has_next) TYPE abap_bool.
+ METHODS get_next
+ RETURNING
+ VALUE(object) TYPE REF TO object.
+ METHODS constructor
+ IMPORTING
+ collection TYPE REF TO ycl_ecb_collection.
+ PROTECTED SECTION.
+ PRIVATE SECTION.
+ DATA index TYPE i VALUE 0.
+ DATA collection TYPE REF TO ycl_ecb_collection.
+ENDCLASS.
+
+
+
+CLASS ycl_ecb_collection_iterator IMPLEMENTATION.
+
+
+ METHOD constructor .
+ me->collection = collection.
+ ENDMETHOD.
+
+
+ METHOD get_index .
+ index = me->index.
+ ENDMETHOD.
+
+
+ METHOD get_next .
+ DATA obj TYPE REF TO object.
+ index = index + 1.
+ object = collection->get( index ).
+ ENDMETHOD.
+
+
+ METHOD has_next.
+ DATA obj TYPE REF TO object.
+ obj = collection->get( index + 1 ).
+ has_next = boolc( obj IS NOT INITIAL ).
+ ENDMETHOD.
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_collection_iterator.clas.xml b/src/abap2xlsx/ycl_ecb_collection_iterator.clas.xml
new file mode 100644
index 0000000..af95f44
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_collection_iterator.clas.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ YCL_ECB_COLLECTION_ITERATOR
+ E
+ abap2xlsx - Object Iterator
+ 1
+ X
+ X
+ X
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb_column.clas.abap b/src/abap2xlsx/ycl_ecb_column.clas.abap
new file mode 100644
index 0000000..c65f18c
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_column.clas.abap
@@ -0,0 +1,229 @@
+CLASS ycl_ecb_column DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+*"* public components of class ZCL_EXCEL_COLUMN
+*"* do not include other source files here!!!
+ PUBLIC SECTION.
+
+ METHODS constructor
+ IMPORTING
+ !ip_index TYPE yecb_cell_column_alpha
+ !ip_worksheet TYPE REF TO ycl_ecb_worksheet
+ !ip_excel TYPE REF TO ycl_ecb
+ RAISING
+ ycx_ecb .
+ METHODS get_auto_size
+ RETURNING
+ VALUE(r_auto_size) TYPE abap_bool .
+ METHODS get_collapsed
+ RETURNING
+ VALUE(r_collapsed) TYPE abap_bool .
+ METHODS get_column_index
+ RETURNING
+ VALUE(r_column_index) TYPE int4 .
+ METHODS get_outline_level
+ RETURNING
+ VALUE(r_outline_level) TYPE int4 .
+ METHODS get_visible
+ RETURNING
+ VALUE(r_visible) TYPE abap_bool .
+ METHODS get_width
+ RETURNING
+ VALUE(r_width) TYPE f .
+ METHODS get_xf_index
+ RETURNING
+ VALUE(r_xf_index) TYPE int4 .
+ METHODS set_auto_size
+ IMPORTING
+ !ip_auto_size TYPE abap_bool
+ RETURNING
+ VALUE(io_column) TYPE REF TO ycl_ecb_column .
+ METHODS set_collapsed
+ IMPORTING
+ !ip_collapsed TYPE abap_bool
+ RETURNING
+ VALUE(io_column) TYPE REF TO ycl_ecb_column .
+ METHODS set_column_index
+ IMPORTING
+ !ip_index TYPE yecb_cell_column_alpha
+ RETURNING
+ VALUE(io_column) TYPE REF TO ycl_ecb_column
+ RAISING
+ ycx_ecb .
+ METHODS set_outline_level
+ IMPORTING
+ !ip_outline_level TYPE int4 .
+ METHODS set_visible
+ IMPORTING
+ !ip_visible TYPE abap_bool
+ RETURNING
+ VALUE(io_column) TYPE REF TO ycl_ecb_column .
+ METHODS set_width
+ IMPORTING
+ !ip_width TYPE simple
+ RETURNING
+ VALUE(io_column) TYPE REF TO ycl_ecb_column
+ RAISING
+ ycx_ecb .
+ METHODS set_xf_index
+ IMPORTING
+ !ip_xf_index TYPE int4
+ RETURNING
+ VALUE(io_column) TYPE REF TO ycl_ecb_column .
+ METHODS set_column_style_by_guid
+ IMPORTING
+ !ip_style_guid TYPE yecb_cell_style
+ RAISING
+ ycx_ecb .
+ METHODS get_column_style_guid
+ RETURNING
+ VALUE(ep_style_guid) TYPE yecb_cell_style
+ RAISING
+ ycx_ecb .
+*"* protected components of class ZCL_EXCEL_COLUMN
+*"* do not include other source files here!!!
+ PROTECTED SECTION.
+*"* private components of class ZCL_EXCEL_COLUMN
+*"* do not include other source files here!!!
+ PRIVATE SECTION.
+
+ DATA column_index TYPE int4 .
+ DATA width TYPE f .
+ DATA auto_size TYPE abap_bool .
+ DATA visible TYPE abap_bool .
+ DATA outline_level TYPE int4 .
+ DATA collapsed TYPE abap_bool .
+ DATA xf_index TYPE int4 .
+ DATA style_guid TYPE yecb_cell_style .
+ DATA excel TYPE REF TO ycl_ecb .
+ DATA worksheet TYPE REF TO ycl_ecb_worksheet .
+ENDCLASS.
+
+
+
+CLASS ycl_ecb_column IMPLEMENTATION.
+
+
+ METHOD constructor.
+ me->column_index = ycl_ecb_common=>convert_column2int( ip_index ).
+ me->width = -1.
+ me->auto_size = abap_false.
+ me->visible = abap_true.
+ me->outline_level = 0.
+ me->collapsed = abap_false.
+ me->excel = ip_excel. "ins issue #157 - Allow Style for columns
+ me->worksheet = ip_worksheet. "ins issue #157 - Allow Style for columns
+
+ " set default index to cellXf
+ me->xf_index = 0.
+
+ ENDMETHOD.
+
+
+ METHOD get_auto_size.
+ r_auto_size = me->auto_size.
+ ENDMETHOD.
+
+
+ METHOD get_collapsed.
+ r_collapsed = me->collapsed.
+ ENDMETHOD.
+
+
+ METHOD get_column_index.
+ r_column_index = me->column_index.
+ ENDMETHOD.
+
+
+ METHOD get_column_style_guid.
+ IF me->style_guid IS NOT INITIAL.
+ ep_style_guid = me->style_guid.
+ ELSE.
+ ep_style_guid = me->worksheet->yif_ecb_sheet_properties~get_style( ).
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD get_outline_level.
+ r_outline_level = me->outline_level.
+ ENDMETHOD.
+
+
+ METHOD get_visible.
+ r_visible = me->visible.
+ ENDMETHOD.
+
+
+ METHOD get_width.
+ r_width = me->width.
+ ENDMETHOD.
+
+
+ METHOD get_xf_index.
+ r_xf_index = me->xf_index.
+ ENDMETHOD.
+
+
+ METHOD set_auto_size.
+ me->auto_size = ip_auto_size.
+ io_column = me.
+ ENDMETHOD.
+
+
+ METHOD set_collapsed.
+ me->collapsed = ip_collapsed.
+ io_column = me.
+ ENDMETHOD.
+
+
+ METHOD set_column_index.
+ me->column_index = ycl_ecb_common=>convert_column2int( ip_index ).
+ io_column = me.
+ ENDMETHOD.
+
+
+ METHOD set_column_style_by_guid.
+ DATA: stylemapping TYPE yecb_s_stylemapping.
+
+ IF me->excel IS NOT BOUND.
+ ycx_ecb=>raise_text( 'Internal error - reference to ZCL_EXCEL not bound' ).
+ ENDIF.
+ TRY.
+ stylemapping = me->excel->get_style_to_guid( ip_style_guid ).
+ me->style_guid = stylemapping-guid.
+
+ CATCH ycx_ecb .
+ RETURN. " leave as is in case of error
+ ENDTRY.
+
+ ENDMETHOD.
+
+
+ METHOD set_outline_level.
+ me->outline_level = ip_outline_level.
+ ENDMETHOD.
+
+
+ METHOD set_visible.
+ me->visible = ip_visible.
+ io_column = me.
+ ENDMETHOD.
+
+
+ METHOD set_width.
+ TRY.
+ me->width = ip_width.
+ io_column = me.
+ CATCH cx_sy_conversion_no_number.
+ ycx_ecb=>raise_text( 'Unable to interpret width as number' ).
+ ENDTRY.
+ ENDMETHOD.
+
+
+ METHOD set_xf_index.
+ me->xf_index = ip_xf_index.
+ io_column = me.
+ ENDMETHOD.
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_column.clas.xml b/src/abap2xlsx/ycl_ecb_column.clas.xml
new file mode 100644
index 0000000..11d1c50
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_column.clas.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+ YCL_ECB_COLUMN
+ E
+ Worksheet Column
+ 1
+ X
+ X
+ X
+
+
+
+ AUTO_SIZE
+ E
+ Auto size?
+
+
+ COLLAPSED
+ E
+ Collapsed?
+
+
+ COLUMN_INDEX
+ E
+ Column index
+
+
+ EXCEL
+ E
+ Excel creator
+
+
+ GET_COLUMN_STYLE_GUID
+ E
+ Get guid of column style
+
+
+ OUTLINE_LEVEL
+ E
+ Outline level
+
+
+ SET_COLUMN_STYLE_BY_GUID
+ E
+ Set column style by style guid
+
+
+ STYLE_GUID
+ E
+ Style identifier
+
+
+ VISIBLE
+ E
+ Visible?
+
+
+ WIDTH
+ E
+ Column width
+
+
+ WORKSHEET
+ E
+ Worksheet
+
+
+ XF_INDEX
+ E
+ Index to cellXf
+
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb_columns.clas.abap b/src/abap2xlsx/ycl_ecb_columns.clas.abap
new file mode 100644
index 0000000..e50ac7b
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_columns.clas.abap
@@ -0,0 +1,107 @@
+CLASS ycl_ecb_columns DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+*"* public components of class ZCL_EXCEL_COLUMNS
+*"* do not include other source files here!!!
+ PUBLIC SECTION.
+ METHODS add
+ IMPORTING
+ !io_column TYPE REF TO ycl_ecb_column .
+ METHODS clear .
+ METHODS constructor .
+ METHODS get
+ IMPORTING
+ !ip_index TYPE i
+ RETURNING
+ VALUE(eo_column) TYPE REF TO ycl_ecb_column .
+ METHODS get_iterator
+ RETURNING
+ VALUE(eo_iterator) TYPE REF TO ycl_ecb_collection_iterator .
+ METHODS is_empty
+ RETURNING
+ VALUE(is_empty) TYPE flag .
+ METHODS remove
+ IMPORTING
+ !io_column TYPE REF TO ycl_ecb_column .
+ METHODS size
+ RETURNING
+ VALUE(ep_size) TYPE i .
+*"* protected components of class ZABAP_EXCEL_WORKSHEETS
+*"* do not include other source files here!!!
+ PROTECTED SECTION.
+*"* private components of class ZABAP_EXCEL_RANGES
+*"* do not include other source files here!!!
+ PRIVATE SECTION.
+ TYPES:
+ BEGIN OF mty_s_hashed_column,
+ column_index TYPE int4,
+ column TYPE REF TO ycl_ecb_column,
+ END OF mty_s_hashed_column ,
+ mty_ts_hashed_column TYPE HASHED TABLE OF mty_s_hashed_column WITH UNIQUE KEY column_index.
+
+ DATA columns TYPE REF TO ycl_ecb_collection .
+ DATA columns_hashed TYPE mty_ts_hashed_column .
+ENDCLASS.
+
+
+
+CLASS ycl_ecb_columns IMPLEMENTATION.
+
+
+ METHOD add.
+ DATA: ls_hashed_column TYPE mty_s_hashed_column.
+
+ ls_hashed_column-column_index = io_column->get_column_index( ).
+ ls_hashed_column-column = io_column.
+
+ INSERT ls_hashed_column INTO TABLE columns_hashed .
+
+ columns->add( io_column ).
+ ENDMETHOD.
+
+
+ METHOD clear.
+ CLEAR columns_hashed.
+ columns->clear( ).
+ ENDMETHOD.
+
+
+ METHOD constructor.
+
+ CREATE OBJECT columns.
+
+ ENDMETHOD.
+
+
+ METHOD get.
+ FIELD-SYMBOLS: TYPE mty_s_hashed_column.
+
+ READ TABLE columns_hashed WITH KEY column_index = ip_index ASSIGNING .
+ IF sy-subrc = 0.
+ eo_column = -column.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD get_iterator.
+ eo_iterator ?= columns->get_iterator( ).
+ ENDMETHOD.
+
+
+ METHOD is_empty.
+ is_empty = columns->is_empty( ).
+ ENDMETHOD.
+
+
+ METHOD remove.
+ DELETE TABLE columns_hashed WITH TABLE KEY column_index = io_column->get_column_index( ) .
+ columns->remove( io_column ).
+ ENDMETHOD.
+
+
+ METHOD size.
+ ep_size = columns->size( ).
+ ENDMETHOD.
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_columns.clas.xml b/src/abap2xlsx/ycl_ecb_columns.clas.xml
new file mode 100644
index 0000000..bc6e6d3
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_columns.clas.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+ YCL_ECB_COLUMNS
+ E
+ Ranges collection
+ 1
+ X
+ X
+ X
+
+
+
+ ADD
+ E
+ Adds an Element to the Collection
+
+
+ CLEAR
+ E
+ Initializes the Collection
+
+
+ CONSTRUCTOR
+ E
+ CONSTRUCTOR
+
+
+ GET
+ E
+ Gets Element
+
+
+ GET_ITERATOR
+ E
+ Returns an iterator
+
+
+ IS_EMPTY
+ E
+ Checks whether elements are contained
+
+
+ REMOVE
+ E
+ Deletes an Element from the Collection
+
+
+ SIZE
+ E
+ Specifies number of contained elements
+
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb_comment.clas.abap b/src/abap2xlsx/ycl_ecb_comment.clas.abap
new file mode 100644
index 0000000..ef03847
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_comment.clas.abap
@@ -0,0 +1,70 @@
+CLASS ycl_ecb_comment DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+
+ METHODS constructor .
+ METHODS get_name
+ RETURNING
+ VALUE(r_name) TYPE string .
+ METHODS get_index
+ RETURNING
+ VALUE(rp_index) TYPE string .
+ METHODS get_ref
+ RETURNING
+ VALUE(rp_ref) TYPE string .
+ METHODS get_text
+ RETURNING
+ VALUE(rp_text) TYPE string .
+ METHODS set_text
+ IMPORTING
+ !ip_text TYPE string
+ !ip_ref TYPE string OPTIONAL .
+ PROTECTED SECTION.
+ PRIVATE SECTION.
+
+ DATA index TYPE string .
+ DATA ref TYPE string .
+ DATA text TYPE string .
+ENDCLASS.
+
+
+
+CLASS ycl_ecb_comment IMPLEMENTATION.
+
+
+ METHOD constructor.
+
+ ENDMETHOD.
+
+
+ METHOD get_index.
+ rp_index = me->index.
+ ENDMETHOD.
+
+
+ METHOD get_name.
+
+ ENDMETHOD.
+
+
+ METHOD get_ref.
+ rp_ref = me->ref.
+ ENDMETHOD.
+
+
+ METHOD get_text.
+ rp_text = me->text.
+ ENDMETHOD.
+
+
+ METHOD set_text.
+ me->text = ip_text.
+
+ IF ip_ref IS SUPPLIED.
+ me->ref = ip_ref.
+ ENDIF.
+ ENDMETHOD.
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_comment.clas.xml b/src/abap2xlsx/ycl_ecb_comment.clas.xml
new file mode 100644
index 0000000..0109307
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_comment.clas.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+ YCL_ECB_COMMENT
+ E
+ Comment
+ 1
+ X
+ X
+ X
+
+
+
+ CONSTRUCTOR
+ E
+ CONSTRUCTOR
+
+
+ GET_INDEX
+ E
+ Get index
+
+
+ GET_REF
+ E
+ Get reference
+
+
+ GET_TEXT
+ E
+ Get text
+
+
+ INDEX
+ E
+ Index in collection
+
+
+ REF
+ E
+ Reference to cell (eg. 'B13')
+
+
+ SET_TEXT
+ E
+ Set text
+
+
+ TEXT
+ E
+ Comment
+
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb_comments.clas.abap b/src/abap2xlsx/ycl_ecb_comments.clas.abap
new file mode 100644
index 0000000..9fedc51
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_comments.clas.abap
@@ -0,0 +1,100 @@
+CLASS ycl_ecb_comments DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+
+ METHODS add
+ IMPORTING
+ !ip_comment TYPE REF TO ycl_ecb_comment .
+ METHODS include
+ IMPORTING
+ !ip_comment TYPE REF TO ycl_ecb_comment .
+ METHODS clear .
+ METHODS constructor .
+ METHODS get
+ IMPORTING
+ !ip_index TYPE yecb_active_worksheet
+ RETURNING
+ VALUE(eo_comment) TYPE REF TO ycl_ecb_comment .
+ METHODS get_iterator
+ RETURNING
+ VALUE(eo_iterator) TYPE REF TO ycl_ecb_collection_iterator .
+ METHODS is_empty
+ RETURNING
+ VALUE(is_empty) TYPE flag .
+ METHODS remove
+ IMPORTING
+ !ip_comment TYPE REF TO ycl_ecb_comment .
+ METHODS size
+ RETURNING
+ VALUE(ep_size) TYPE i .
+ PROTECTED SECTION.
+ PRIVATE SECTION.
+
+ DATA comments TYPE REF TO ycl_ecb_collection .
+ENDCLASS.
+
+
+
+CLASS ycl_ecb_comments IMPLEMENTATION.
+
+
+ METHOD add.
+ DATA: lv_index TYPE i.
+
+ comments->add( ip_comment ).
+ lv_index = comments->size( ).
+
+ ENDMETHOD.
+
+
+ METHOD clear.
+ comments->clear( ).
+
+ ENDMETHOD.
+
+
+ METHOD constructor.
+ CREATE OBJECT comments.
+
+ ENDMETHOD.
+
+
+ METHOD get.
+ DATA lv_index TYPE i.
+ lv_index = ip_index.
+ eo_comment ?= comments->get( lv_index ).
+
+ ENDMETHOD.
+
+
+ METHOD get_iterator.
+
+ eo_iterator ?= comments->get_iterator( ).
+ ENDMETHOD.
+
+
+ METHOD include.
+ comments->add( ip_comment ).
+ ENDMETHOD.
+
+
+ METHOD is_empty.
+
+ is_empty = comments->is_empty( ).
+ ENDMETHOD.
+
+
+ METHOD remove.
+
+ comments->remove( ip_comment ).
+ ENDMETHOD.
+
+
+ METHOD size.
+
+ ep_size = comments->size( ).
+ ENDMETHOD.
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_comments.clas.xml b/src/abap2xlsx/ycl_ecb_comments.clas.xml
new file mode 100644
index 0000000..f399c11
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_comments.clas.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+ YCL_ECB_COMMENTS
+ E
+ Comments collection
+ 1
+ X
+ X
+ X
+
+
+
+ ADD
+ E
+ Adds an Element to the Collection
+
+
+ CLEAR
+ E
+ Initializes the Collection
+
+
+ CONSTRUCTOR
+ E
+ CONSTRUCTOR
+
+
+ GET
+ E
+ Gets Element
+
+
+ GET_ITERATOR
+ E
+ Returns an iterator
+
+
+ INCLUDE
+ E
+ Adds an Element to the Collection
+
+
+ IS_EMPTY
+ E
+ Checks whether elements are contained
+
+
+ REMOVE
+ E
+ Deletes an Element from the Collection
+
+
+ SIZE
+ E
+ Specifies number of contained elements
+
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb_common.clas.abap b/src/abap2xlsx/ycl_ecb_common.clas.abap
new file mode 100644
index 0000000..c25e78f
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_common.clas.abap
@@ -0,0 +1,1709 @@
+CLASS ycl_ecb_common DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+*"* public components of class ZCL_EXCEL_COMMON
+*"* do not include other source files here!!!
+ PUBLIC SECTION.
+
+ CONSTANTS c_excel_baseline_date TYPE d VALUE '19000101'. "#EC NOTEXT
+ CLASS-DATA c_excel_numfmt_offset TYPE int1 VALUE 164. "#EC NOTEXT . . . . . . . . . . . . . . . . " .
+ CONSTANTS c_excel_sheet_max_col TYPE int4 VALUE 16384. "#EC NOTEXT
+ CONSTANTS c_excel_sheet_min_col TYPE int4 VALUE 1. "#EC NOTEXT
+ CONSTANTS c_excel_sheet_max_row TYPE int4 VALUE 1048576. "#EC NOTEXT
+ CONSTANTS c_excel_sheet_min_row TYPE int4 VALUE 1. "#EC NOTEXT
+ CLASS-DATA c_spras_en TYPE spras VALUE 'E'. "#EC NOTEXT . . . . . . . . . . . . . . . . " .
+ CLASS-DATA o_conv TYPE REF TO cl_abap_conv_out_ce .
+ CONSTANTS c_excel_1900_leap_year TYPE d VALUE '19000228'. "#EC NOTEXT
+ CLASS-DATA c_xlsx_file_filter TYPE string VALUE 'Excel Workbook (*.xlsx)|*.xlsx|'. "#EC NOTEXT . . . . . . . " .
+
+ CLASS-METHODS class_constructor .
+ CLASS-METHODS describe_structure
+ IMPORTING
+ !io_struct TYPE REF TO cl_abap_structdescr
+ RETURNING
+ VALUE(rt_dfies) TYPE ddfields .
+ CLASS-METHODS convert_column2alpha
+ IMPORTING
+ !ip_column TYPE simple
+ RETURNING
+ VALUE(ep_column) TYPE yecb_cell_column_alpha
+ RAISING
+ ycx_ecb .
+ CLASS-METHODS convert_column2int
+ IMPORTING
+ !ip_column TYPE simple
+ RETURNING
+ VALUE(ep_column) TYPE yecb_cell_column
+ RAISING
+ ycx_ecb .
+ CLASS-METHODS convert_column_a_row2columnrow
+ IMPORTING
+ !i_column TYPE simple
+ !i_row TYPE yecb_cell_row
+ RETURNING
+ VALUE(e_columnrow) TYPE string
+ RAISING
+ ycx_ecb.
+ CLASS-METHODS convert_columnrow2column_a_row
+ IMPORTING
+ !i_columnrow TYPE clike
+ EXPORTING
+ !e_column TYPE yecb_cell_column_alpha
+ !e_column_int TYPE yecb_cell_column
+ !e_row TYPE yecb_cell_row
+ RAISING
+ ycx_ecb.
+ CLASS-METHODS convert_range2column_a_row
+ IMPORTING
+ !i_range TYPE clike
+ !i_allow_1dim_range TYPE abap_bool DEFAULT abap_false
+ EXPORTING
+ !e_column_start TYPE yecb_cell_column_alpha
+ !e_column_start_int TYPE yecb_cell_column
+ !e_column_end TYPE yecb_cell_column_alpha
+ !e_column_end_int TYPE yecb_cell_column
+ !e_row_start TYPE yecb_cell_row
+ !e_row_end TYPE yecb_cell_row
+ !e_sheet TYPE clike
+ RAISING
+ ycx_ecb .
+ CLASS-METHODS convert_columnrow2column_o_row
+ IMPORTING
+ !i_columnrow TYPE clike
+ EXPORTING
+ !e_column TYPE yecb_cell_column_alpha
+ !e_row TYPE yecb_cell_row .
+ CLASS-METHODS clone_ixml_with_namespaces
+ IMPORTING
+ element TYPE REF TO if_ixml_element
+ RETURNING
+ VALUE(result) TYPE REF TO if_ixml_element.
+ CLASS-METHODS date_to_excel_string
+ IMPORTING
+ !ip_value TYPE d
+ RETURNING
+ VALUE(ep_value) TYPE yecb_cell_value .
+ CLASS-METHODS encrypt_password
+ IMPORTING
+ !i_pwd TYPE yecb_aes_password
+ RETURNING
+ VALUE(r_encrypted_pwd) TYPE yecb_aes_password .
+ CLASS-METHODS escape_string
+ IMPORTING
+ !ip_value TYPE clike
+ RETURNING
+ VALUE(ep_escaped_value) TYPE string .
+ CLASS-METHODS unescape_string
+ IMPORTING
+ !iv_escaped TYPE clike
+ RETURNING
+ VALUE(ev_unescaped_string) TYPE string
+ RAISING
+ ycx_ecb .
+ CLASS-METHODS excel_string_to_date
+ IMPORTING
+ !ip_value TYPE yecb_cell_value
+ RETURNING
+ VALUE(ep_value) TYPE d
+ RAISING
+ ycx_ecb .
+ CLASS-METHODS excel_string_to_time
+ IMPORTING
+ !ip_value TYPE yecb_cell_value
+ RETURNING
+ VALUE(ep_value) TYPE t
+ RAISING
+ ycx_ecb .
+ CLASS-METHODS excel_string_to_number
+ IMPORTING
+ !ip_value TYPE yecb_cell_value
+ RETURNING
+ VALUE(ep_value) TYPE f
+ RAISING
+ ycx_ecb .
+ CLASS-METHODS get_fieldcatalog
+ IMPORTING
+ !ip_table TYPE STANDARD TABLE
+ !iv_hide_mandt TYPE abap_bool DEFAULT abap_true
+ !ip_conv_exit_length TYPE abap_bool DEFAULT abap_false
+ RETURNING
+ VALUE(ep_fieldcatalog) TYPE yecb_t_fieldcatalog .
+ CLASS-METHODS number_to_excel_string
+ IMPORTING
+ VALUE(ip_value) TYPE numeric
+ ip_currency TYPE waers_curc OPTIONAL
+ RETURNING
+ VALUE(ep_value) TYPE yecb_cell_value .
+ CLASS-METHODS recursive_class_to_struct
+ IMPORTING
+ !i_source TYPE any
+ CHANGING
+ !e_target TYPE data
+ !e_targetx TYPE data .
+ CLASS-METHODS recursive_struct_to_class
+ IMPORTING
+ !i_source TYPE data
+ !i_sourcex TYPE data
+ CHANGING
+ !e_target TYPE any .
+ CLASS-METHODS time_to_excel_string
+ IMPORTING
+ !ip_value TYPE t
+ RETURNING
+ VALUE(ep_value) TYPE yecb_cell_value .
+ TYPES: t_char10 TYPE c LENGTH 10.
+ TYPES: t_char255 TYPE c LENGTH 255.
+ CLASS-METHODS split_file
+ IMPORTING
+ !ip_file TYPE t_char255
+ EXPORTING
+ !ep_file TYPE t_char255
+ !ep_extension TYPE t_char10
+ !ep_dotextension TYPE t_char10 .
+ CLASS-METHODS calculate_cell_distance
+ IMPORTING
+ !iv_reference_cell TYPE clike
+ !iv_current_cell TYPE clike
+ EXPORTING
+ !ev_row_difference TYPE i
+ !ev_col_difference TYPE i
+ RAISING
+ ycx_ecb .
+ CLASS-METHODS determine_resulting_formula
+ IMPORTING
+ !iv_reference_cell TYPE clike
+ !iv_reference_formula TYPE clike
+ !iv_current_cell TYPE clike
+ RETURNING
+ VALUE(ev_resulting_formula) TYPE string
+ RAISING
+ ycx_ecb .
+ CLASS-METHODS shift_formula
+ IMPORTING
+ !iv_reference_formula TYPE clike
+ VALUE(iv_shift_cols) TYPE i
+ VALUE(iv_shift_rows) TYPE i
+ RETURNING
+ VALUE(ev_resulting_formula) TYPE string
+ RAISING
+ ycx_ecb .
+ CLASS-METHODS is_cell_in_range
+ IMPORTING
+ !ip_column TYPE simple
+ !ip_row TYPE yecb_cell_row
+ !ip_range TYPE clike
+ RETURNING
+ VALUE(rp_in_range) TYPE abap_bool
+ RAISING
+ ycx_ecb .
+*"* protected components of class ZCL_EXCEL_COMMON
+*"* do not include other source files here!!!
+*"* protected components of class ZCL_EXCEL_COMMON
+*"* do not include other source files here!!!
+ PROTECTED SECTION.
+ PRIVATE SECTION.
+
+ CLASS-DATA c_excel_col_module TYPE int2 VALUE 64. "#EC NOTEXT . . . . . . . . . . . . . . . " .
+ CLASS-DATA sv_prev_in1 TYPE yecb_cell_column.
+ CLASS-DATA sv_prev_out1 TYPE yecb_cell_column_alpha.
+ CLASS-DATA sv_prev_in2 TYPE c LENGTH 10.
+ CLASS-DATA sv_prev_out2 TYPE yecb_cell_column.
+ CLASS-METHODS structure_case
+ IMPORTING
+ !is_component TYPE abap_componentdescr
+ CHANGING
+ !xt_components TYPE abap_component_tab .
+ CLASS-METHODS structure_recursive
+ IMPORTING
+ !is_component TYPE abap_componentdescr
+ RETURNING
+ VALUE(rt_components) TYPE abap_component_tab .
+ TYPES ty_char1 TYPE c LENGTH 1.
+ CLASS-METHODS char2hex
+ IMPORTING
+ !i_char TYPE ty_char1
+ RETURNING
+ VALUE(r_hex) TYPE yecb_pwd_hash .
+ CLASS-METHODS shl01
+ IMPORTING
+ !i_pwd_hash TYPE yecb_pwd_hash
+ RETURNING
+ VALUE(r_pwd_hash) TYPE yecb_pwd_hash .
+ CLASS-METHODS shr14
+ IMPORTING
+ !i_pwd_hash TYPE yecb_pwd_hash
+ RETURNING
+ VALUE(r_pwd_hash) TYPE yecb_pwd_hash .
+ENDCLASS.
+
+
+
+CLASS ycl_ecb_common IMPLEMENTATION.
+
+
+ METHOD calculate_cell_distance.
+
+ DATA: lv_reference_row TYPE i,
+ lv_reference_col_alpha TYPE yecb_cell_column_alpha,
+ lv_reference_col TYPE i,
+ lv_current_row TYPE i,
+ lv_current_col_alpha TYPE yecb_cell_column_alpha,
+ lv_current_col TYPE i.
+
+*--------------------------------------------------------------------*
+* Split reference cell into numerical row/column representation
+*--------------------------------------------------------------------*
+ convert_columnrow2column_a_row( EXPORTING
+ i_columnrow = iv_reference_cell
+ IMPORTING
+ e_column = lv_reference_col_alpha
+ e_row = lv_reference_row ).
+ lv_reference_col = convert_column2int( lv_reference_col_alpha ).
+
+*--------------------------------------------------------------------*
+* Split current cell into numerical row/column representation
+*--------------------------------------------------------------------*
+ convert_columnrow2column_a_row( EXPORTING
+ i_columnrow = iv_current_cell
+ IMPORTING
+ e_column = lv_current_col_alpha
+ e_row = lv_current_row ).
+ lv_current_col = convert_column2int( lv_current_col_alpha ).
+
+*--------------------------------------------------------------------*
+* Calculate row and column difference
+* Positive: Current cell below reference cell
+* or Current cell right of reference cell
+* Negative: Current cell above reference cell
+* or Current cell left of reference cell
+*--------------------------------------------------------------------*
+ ev_row_difference = lv_current_row - lv_reference_row.
+ ev_col_difference = lv_current_col - lv_reference_col.
+
+ ENDMETHOD.
+
+
+ METHOD char2hex.
+
+ IF o_conv IS NOT BOUND.
+ o_conv = cl_abap_conv_out_ce=>create( endian = 'L'
+ ignore_cerr = abap_true
+ replacement = '#' ).
+ ENDIF.
+
+ CALL METHOD o_conv->reset( ).
+ CALL METHOD o_conv->write( data = i_char ).
+ r_hex+1 = o_conv->get_buffer( ). " x'65' must be x'0065'
+
+ ENDMETHOD.
+
+
+ METHOD class_constructor.
+ c_xlsx_file_filter = 'Excel Workbook (*.xlsx)|*.xlsx|'(005).
+ ENDMETHOD.
+
+
+ METHOD convert_column2alpha.
+
+ DATA: lv_uccpi TYPE i,
+ lv_text TYPE c LENGTH 2,
+ lv_module TYPE int4,
+ lv_column TYPE yecb_cell_column.
+
+* Propagate zcx_excel if error occurs " issue #155 - less restrictive typing for ip_column
+ lv_column = convert_column2int( ip_column ). " issue #155 - less restrictive typing for ip_column
+
+*--------------------------------------------------------------------*
+* Check whether column is in allowed range for EXCEL to handle ( 1-16384 )
+*--------------------------------------------------------------------*
+ IF lv_column > 16384
+ OR lv_column < 1.
+ ycx_ecb=>raise_text( 'Index out of bounds' ).
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Look up for previous succesfull cached result
+*--------------------------------------------------------------------*
+ IF lv_column = sv_prev_in1 AND sv_prev_out1 IS NOT INITIAL.
+ ep_column = sv_prev_out1.
+ RETURN.
+ ELSE.
+ CLEAR sv_prev_out1.
+ sv_prev_in1 = lv_column.
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Build alpha representation of column
+*--------------------------------------------------------------------*
+ WHILE lv_column GT 0.
+
+ lv_module = ( lv_column - 1 ) MOD 26.
+ lv_uccpi = 65 + lv_module.
+
+ lv_column = ( lv_column - lv_module ) / 26.
+
+ lv_text = cl_abap_conv_in_ce=>uccpi( lv_uccpi ).
+ CONCATENATE lv_text ep_column INTO ep_column.
+
+ ENDWHILE.
+
+*--------------------------------------------------------------------*
+* Save succesfull output into cache
+*--------------------------------------------------------------------*
+ sv_prev_out1 = ep_column.
+
+ ENDMETHOD.
+
+
+ METHOD convert_column2int.
+
+*--------------------------------------------------------------------*
+* issue #230 - Pimp my Code
+* - Stefan Schmoecker, (done) 2012-12-29
+* - ...
+* changes: renaming variables to naming conventions
+* removing unused variables
+* removing commented out code that is inactive for more then half a year
+* message made to support multilinguality
+* adding comments to explain what we are trying to achieve
+*--------------------------------------------------------------------*
+* issue#246 - error converting lower case column names
+* - Stefan Schmoecker, 2012-12-29
+* changes: translating the correct variable to upper dase
+* adding missing exception if input is a number
+* that is out of bounds
+* adding missing exception if input contains
+* illegal characters like german umlauts
+*--------------------------------------------------------------------*
+
+ DATA: lv_column TYPE yecb_cell_column_alpha,
+ lv_column_c TYPE c LENGTH 10,
+ lv_column_s TYPE string,
+ lv_errormessage TYPE string, " Can't pass '...'(abc) to exception-class
+ lv_modulo TYPE i.
+
+*--------------------------------------------------------------------*
+* This module tries to identify which column a user wants to access
+* Numbers as input are just passed back, anything else will be converted
+* using EXCEL nomenclatura A = 1, AA = 27, ..., XFD = 16384
+*--------------------------------------------------------------------*
+
+*--------------------------------------------------------------------*
+* Normalize input ( upper case , no gaps )
+*--------------------------------------------------------------------*
+ lv_column_c = ip_column.
+ TRANSLATE lv_column_c TO UPPER CASE. " Fix #246
+ CONDENSE lv_column_c NO-GAPS.
+ IF lv_column_c EQ ''.
+ MESSAGE e800(yecb) INTO lv_errormessage.
+ ycx_ecb=>raise_symsg( ).
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Look up for previous succesfull cached result
+*--------------------------------------------------------------------*
+ IF lv_column_c = sv_prev_in2 AND sv_prev_out2 IS NOT INITIAL.
+ ep_column = sv_prev_out2.
+ RETURN.
+ ELSE.
+ CLEAR sv_prev_out2.
+ sv_prev_in2 = lv_column_c.
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* If a number gets passed, just convert it to an integer and return
+* the converted value
+*--------------------------------------------------------------------*
+ TRY.
+ IF lv_column_c CO '1234567890 '. " Fix #164
+ ep_column = lv_column_c. " Fix #164
+*--------------------------------------------------------------------*
+* Maximum column for EXCEL: XFD = 16384 " if anyone has a reference for this information - please add here instead of this comment
+*--------------------------------------------------------------------*
+ IF ep_column > 16384 OR ep_column < 1.
+ lv_errormessage = 'Index out of bounds'(004).
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDIF.
+ RETURN.
+ ENDIF.
+ CATCH cx_sy_conversion_no_number. "#EC NO_HANDLER
+ " Try the character-approach if approach via number has failed
+ ENDTRY.
+
+*--------------------------------------------------------------------*
+* Raise error if unexpected characters turns up
+*--------------------------------------------------------------------*
+ lv_column_s = lv_column_c.
+ IF lv_column_s CN sy-abcde.
+ MESSAGE e800(yecb) INTO lv_errormessage.
+ ycx_ecb=>raise_symsg( ).
+ ENDIF.
+
+ DO 1 TIMES. "Because of using CHECK
+*--------------------------------------------------------------------*
+* Interpret input as number to base 26 with A=1, ... Z=26
+* Raise error if unexpected character turns up
+*--------------------------------------------------------------------*
+* 1st character
+*--------------------------------------------------------------------*
+ lv_column = lv_column_c.
+ FIND lv_column+0(1) IN sy-abcde MATCH OFFSET lv_modulo.
+ lv_modulo = lv_modulo + 1.
+ IF lv_modulo < 1 OR lv_modulo > 26.
+ MESSAGE e800(yecb) INTO lv_errormessage.
+ ycx_ecb=>raise_symsg( ).
+ ENDIF.
+ ep_column = lv_modulo. " Leftmost digit
+
+*--------------------------------------------------------------------*
+* 2nd character if present
+*--------------------------------------------------------------------*
+ CHECK lv_column+1(1) IS NOT INITIAL. " No need to continue if string ended
+ FIND lv_column+1(1) IN sy-abcde MATCH OFFSET lv_modulo.
+ lv_modulo = lv_modulo + 1.
+ IF lv_modulo < 1 OR lv_modulo > 26.
+ MESSAGE e800(yecb) INTO lv_errormessage.
+ ycx_ecb=>raise_symsg( ).
+ ENDIF.
+ ep_column = 26 * ep_column + lv_modulo. " if second digit is present first digit is for 26^1
+
+*--------------------------------------------------------------------*
+* 3rd character if present
+*--------------------------------------------------------------------*
+ CHECK lv_column+2(1) IS NOT INITIAL. " No need to continue if string ended
+ FIND lv_column+2(1) IN sy-abcde MATCH OFFSET lv_modulo.
+ lv_modulo = lv_modulo + 1.
+ IF lv_modulo < 1 OR lv_modulo > 26.
+ MESSAGE e800(yecb) INTO lv_errormessage.
+ ycx_ecb=>raise_symsg( ).
+ ENDIF.
+ ep_column = 26 * ep_column + lv_modulo. " if third digit is present first digit is for 26^2 and second digit for 26^1
+ ENDDO.
+
+*--------------------------------------------------------------------*
+* Maximum column for EXCEL: XFD = 16384 " if anyone has a reference for this information - please add here instead of this comment
+*--------------------------------------------------------------------*
+ IF ep_column > 16384 OR ep_column < 1.
+ lv_errormessage = 'Index out of bounds'(004).
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Save succesfull output into cache
+*--------------------------------------------------------------------*
+ sv_prev_out2 = ep_column.
+
+ ENDMETHOD.
+
+
+ METHOD convert_column_a_row2columnrow.
+ DATA: lv_row_alpha TYPE string,
+ lv_column_alpha TYPE yecb_cell_column_alpha.
+
+ lv_row_alpha = i_row.
+ lv_column_alpha = ycl_ecb_common=>convert_column2alpha( i_column ).
+ SHIFT lv_row_alpha RIGHT DELETING TRAILING space.
+ SHIFT lv_row_alpha LEFT DELETING LEADING space.
+ CONCATENATE lv_column_alpha lv_row_alpha INTO e_columnrow.
+
+ ENDMETHOD.
+
+
+ METHOD convert_columnrow2column_a_row.
+*--------------------------------------------------------------------*
+ "issue #256 - replacing char processing with regex
+*--------------------------------------------------------------------*
+* Stefan Schmoecker, 2013-08-11
+* Allow input to be CLIKE instead of STRING
+*--------------------------------------------------------------------*
+
+ DATA: pane_cell_row_a TYPE string,
+ lv_columnrow TYPE string.
+
+ lv_columnrow = i_columnrow. " Get rid of trailing blanks
+
+ FIND REGEX '^(\D+)(\d+)$' IN lv_columnrow SUBMATCHES e_column
+ pane_cell_row_a.
+ IF e_column_int IS SUPPLIED.
+ e_column_int = convert_column2int( ip_column = e_column ).
+ ENDIF.
+ e_row = pane_cell_row_a.
+
+ ENDMETHOD.
+
+
+ METHOD convert_range2column_a_row.
+*--------------------------------------------------------------------*
+* issue #230 - Pimp my Code
+* - Stefan Schmoecker, (done) 2012-12-07
+* - ...
+* changes: renaming variables to naming conventions
+* aligning code
+* added exceptionclass
+* added errorhandling for invalid range
+* adding comments to explain what we are trying to achieve
+*--------------------------------------------------------------------*
+* issue#241 - error when sheetname contains "!"
+* - sheetname should be returned unescaped
+* - Stefan Schmoecker, 2012-12-07
+* changes: changed coding to support sheetnames with "!"
+* unescaping sheetname
+*--------------------------------------------------------------------*
+* issue#155 - lessening restrictions of input parameters
+* - Stefan Schmoecker, 2012-12-07
+* changes: i_range changed to clike
+* e_sheet changed to clike
+*--------------------------------------------------------------------*
+
+ DATA: lv_sheet TYPE string,
+ lv_range TYPE string,
+ lv_columnrow_start TYPE string,
+ lv_columnrow_end TYPE string,
+ lv_position TYPE i,
+ lv_errormessage TYPE string. " Can't pass '...'(abc) to exception-class
+
+
+*--------------------------------------------------------------------*
+* Split input range into sheetname and Area
+* 4 cases - a) input empty --> nothing to do
+* - b) sheetname existing - starts with ' example 'Sheet 1'!$B$6:$D$13
+* - c) sheetname existing - does not start with ' example Sheet1!$B$6:$D$13
+* - d) no sheetname - just area example $B$6:$D$13
+*--------------------------------------------------------------------*
+* Initialize output parameters
+ CLEAR: e_column_start,
+ e_column_end,
+ e_row_start,
+ e_row_end,
+ e_sheet.
+
+ IF i_range IS INITIAL. " a) input empty --> nothing to do
+ RETURN.
+
+ ELSEIF i_range(1) = `'`. " b) sheetname existing - starts with '
+ FIND REGEX '\![^\!]*$' IN i_range MATCH OFFSET lv_position. " Find last !
+ IF sy-subrc = 0.
+ lv_sheet = i_range(lv_position).
+ ADD 1 TO lv_position.
+ lv_range = i_range.
+ SHIFT lv_range LEFT BY lv_position PLACES.
+ ELSE.
+ lv_errormessage = 'Invalid range'(001).
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDIF.
+
+ ELSEIF i_range CS '!'. " c) sheetname existing - does not start with '
+ SPLIT i_range AT '!' INTO lv_sheet lv_range.
+ " begin Dennis Schaaf
+ IF lv_range CP '*#REF*'.
+ lv_errormessage = 'Invalid range'(001).
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDIF.
+ " end Dennis Schaaf
+ ELSE. " d) no sheetname - just area
+ lv_range = i_range.
+ ENDIF.
+
+ REPLACE ALL OCCURRENCES OF '$' IN lv_range WITH ''.
+ SPLIT lv_range AT ':' INTO lv_columnrow_start lv_columnrow_end.
+
+ IF i_allow_1dim_range = abap_true.
+ convert_columnrow2column_o_row( EXPORTING i_columnrow = lv_columnrow_start
+ IMPORTING e_column = e_column_start
+ e_row = e_row_start ).
+ convert_columnrow2column_o_row( EXPORTING i_columnrow = lv_columnrow_end
+ IMPORTING e_column = e_column_end
+ e_row = e_row_end ).
+ ELSE.
+ convert_columnrow2column_a_row( EXPORTING i_columnrow = lv_columnrow_start
+ IMPORTING e_column = e_column_start
+ e_row = e_row_start ).
+ convert_columnrow2column_a_row( EXPORTING i_columnrow = lv_columnrow_end
+ IMPORTING e_column = e_column_end
+ e_row = e_row_end ).
+ ENDIF.
+
+ IF e_column_start_int IS SUPPLIED AND e_column_start IS NOT INITIAL.
+ e_column_start_int = convert_column2int( e_column_start ).
+ ENDIF.
+ IF e_column_end_int IS SUPPLIED AND e_column_end IS NOT INITIAL.
+ e_column_end_int = convert_column2int( e_column_end ).
+ ENDIF.
+
+ e_sheet = unescape_string( lv_sheet ). " Return in unescaped form
+ ENDMETHOD.
+
+
+ METHOD convert_columnrow2column_o_row.
+
+ DATA: row TYPE string.
+ DATA: columnrow TYPE string.
+
+ CLEAR e_column.
+
+ columnrow = i_columnrow.
+
+ FIND REGEX '^(\D*)(\d*)$' IN columnrow SUBMATCHES e_column
+ row.
+
+ e_row = row.
+
+ ENDMETHOD.
+
+
+ METHOD clone_ixml_with_namespaces.
+
+ DATA: iterator TYPE REF TO if_ixml_node_iterator,
+ node TYPE REF TO if_ixml_node,
+ xmlns TYPE ihttpnvp,
+ xmlns_table TYPE TABLE OF ihttpnvp.
+ FIELD-SYMBOLS:
+ TYPE ihttpnvp.
+
+ iterator = element->create_iterator( ).
+ result ?= element->clone( ).
+ node = iterator->get_next( ).
+ WHILE node IS BOUND.
+ xmlns-name = node->get_namespace_prefix( ).
+ xmlns-value = node->get_namespace_uri( ).
+ COLLECT xmlns INTO xmlns_table.
+ node = iterator->get_next( ).
+ ENDWHILE.
+
+ LOOP AT xmlns_table ASSIGNING .
+ result->set_attribute_ns( prefix = 'xmlns' name = -name value = -value ).
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+ METHOD date_to_excel_string.
+ DATA: lv_date_diff TYPE i.
+
+ CHECK ip_value IS NOT INITIAL
+ AND ip_value <> space.
+ " Needed hack caused by the problem that:
+ " Excel 2000 incorrectly assumes that the year 1900 is a leap year
+ " http://support.microsoft.com/kb/214326/en-us
+ IF ip_value > c_excel_1900_leap_year.
+ lv_date_diff = ip_value - c_excel_baseline_date + 2.
+ ELSE.
+ lv_date_diff = ip_value - c_excel_baseline_date + 1.
+ ENDIF.
+ ep_value = ycl_ecb_common=>number_to_excel_string( ip_value = lv_date_diff ).
+ ENDMETHOD.
+
+
+ METHOD describe_structure.
+ DATA: lt_components TYPE abap_component_tab,
+ lt_comps TYPE abap_component_tab,
+ ls_component TYPE abap_componentdescr,
+ lo_elemdescr TYPE REF TO cl_abap_elemdescr,
+ ls_dfies TYPE dfies,
+ l_position LIKE ls_dfies-position.
+
+ "for DDIC structure get the info directly
+ IF io_struct->is_ddic_type( ) = abap_true.
+ rt_dfies = io_struct->get_ddic_field_list( ).
+ ELSE.
+ lt_components = io_struct->get_components( ).
+
+ LOOP AT lt_components INTO ls_component.
+ structure_case( EXPORTING is_component = ls_component
+ CHANGING xt_components = lt_comps ) .
+ ENDLOOP.
+ LOOP AT lt_comps INTO ls_component.
+ CLEAR ls_dfies.
+ IF ls_component-type->kind = cl_abap_typedescr=>kind_elem. "E Elementary Type
+ ADD 1 TO l_position.
+ lo_elemdescr ?= ls_component-type.
+ IF lo_elemdescr->is_ddic_type( ) = abap_true.
+ ls_dfies = lo_elemdescr->get_ddic_field( ).
+ ls_dfies-fieldname = ls_component-name.
+ ls_dfies-position = l_position.
+ ELSE.
+ ls_dfies-fieldname = ls_component-name.
+ ls_dfies-position = l_position.
+ ls_dfies-inttype = lo_elemdescr->type_kind.
+ ls_dfies-leng = lo_elemdescr->length.
+ ls_dfies-outputlen = lo_elemdescr->length.
+ ls_dfies-decimals = lo_elemdescr->decimals.
+ ls_dfies-fieldtext = ls_component-name.
+ ls_dfies-reptext = ls_component-name.
+ ls_dfies-scrtext_s = ls_component-name.
+ ls_dfies-scrtext_m = ls_component-name.
+ ls_dfies-scrtext_l = ls_component-name.
+ ls_dfies-dynpfld = abap_true.
+ ENDIF.
+ INSERT ls_dfies INTO TABLE rt_dfies.
+ ENDIF.
+ ENDLOOP.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD determine_resulting_formula.
+
+ DATA: lv_row_difference TYPE i,
+ lv_col_difference TYPE i.
+
+*--------------------------------------------------------------------*
+* Calculate distance of reference and current cell
+*--------------------------------------------------------------------*
+ calculate_cell_distance( EXPORTING
+ iv_reference_cell = iv_reference_cell
+ iv_current_cell = iv_current_cell
+ IMPORTING
+ ev_row_difference = lv_row_difference
+ ev_col_difference = lv_col_difference ).
+
+*--------------------------------------------------------------------*
+* and shift formula by using the row- and columndistance
+*--------------------------------------------------------------------*
+ ev_resulting_formula = shift_formula( iv_reference_formula = iv_reference_formula
+ iv_shift_rows = lv_row_difference
+ iv_shift_cols = lv_col_difference ).
+
+ ENDMETHOD. "determine_resulting_formula
+
+
+ METHOD encrypt_password.
+
+ DATA lv_curr_offset TYPE i.
+ DATA lv_curr_char TYPE c LENGTH 1.
+ DATA lv_curr_hex TYPE yecb_pwd_hash.
+ DATA lv_pwd_len TYPE yecb_pwd_hash.
+ DATA lv_pwd_hash TYPE yecb_pwd_hash.
+
+ CONSTANTS:
+ lv_0x7fff TYPE yecb_pwd_hash VALUE '7FFF',
+ lv_0x0001 TYPE yecb_pwd_hash VALUE '0001',
+ lv_0xce4b TYPE yecb_pwd_hash VALUE 'CE4B'.
+
+ DATA lv_pwd TYPE yecb_aes_password.
+
+ lv_pwd = i_pwd.
+
+ lv_pwd_len = strlen( lv_pwd ).
+ lv_curr_offset = lv_pwd_len - 1.
+
+ WHILE lv_curr_offset GE 0.
+
+ lv_curr_char = lv_pwd+lv_curr_offset(1).
+ lv_curr_hex = char2hex( lv_curr_char ).
+
+ lv_pwd_hash = ( shr14( lv_pwd_hash ) BIT-AND lv_0x0001 ) BIT-OR ( shl01( lv_pwd_hash ) BIT-AND lv_0x7fff ).
+
+ lv_pwd_hash = lv_pwd_hash BIT-XOR lv_curr_hex.
+ SUBTRACT 1 FROM lv_curr_offset.
+ ENDWHILE.
+
+ lv_pwd_hash = ( shr14( lv_pwd_hash ) BIT-AND lv_0x0001 ) BIT-OR ( shl01( lv_pwd_hash ) BIT-AND lv_0x7fff ).
+ lv_pwd_hash = lv_pwd_hash BIT-XOR lv_0xce4b.
+ lv_pwd_hash = lv_pwd_hash BIT-XOR lv_pwd_len.
+
+ WRITE lv_pwd_hash TO r_encrypted_pwd.
+
+ ENDMETHOD.
+
+
+ METHOD escape_string.
+*--------------------------------------------------------------------*
+* issue #230 - Pimp my Code
+* - Stefan Schmoecker, (done) 2012-12-08
+* - ...
+* changes: aligning code
+* adding comments to explain what we are trying to achieve
+*--------------------------------------------------------------------*
+* issue#242 - Support escaping for white-spaces
+* - Escaping also necessary when ' encountered in input
+* - Stefan Schmoecker, 2012-12-08
+* changes: switched check if escaping is necessary to regular expression
+* and moved the "REPLACE"
+*--------------------------------------------------------------------*
+* issue#155 - lessening restrictions of input parameters
+* - Stefan Schmoecker, 2012-12-08
+* changes: ip_value changed to clike
+*--------------------------------------------------------------------*
+ DATA: lv_value TYPE string.
+
+*--------------------------------------------------------------------*
+* There exist various situations when a space will be used to separate
+* different parts of a string. When we have a string consisting spaces
+* that will cause errors unless we "escape" the string by putting ' at
+* the beginning and at the end of the string.
+*--------------------------------------------------------------------*
+
+
+*--------------------------------------------------------------------*
+* When allowing clike-input parameters we might encounter trailing
+* "real" blanks . These are automatically eliminated when moving
+* the input parameter to a string.
+* Now any remaining spaces ( white-spaces or normal spaces ) should
+* trigger the escaping as well as any '
+*--------------------------------------------------------------------*
+ lv_value = ip_value.
+
+
+ FIND REGEX `\s|'|-` IN lv_value. " \s finds regular and white spaces
+ IF sy-subrc = 0.
+ REPLACE ALL OCCURRENCES OF `'` IN lv_value WITH `''`.
+ CONCATENATE `'` lv_value `'` INTO lv_value .
+ ENDIF.
+
+ ep_escaped_value = lv_value.
+
+ ENDMETHOD.
+
+
+ METHOD excel_string_to_date.
+ DATA: lv_date_int TYPE i.
+
+ CHECK ip_value IS NOT INITIAL AND ip_value CN ' 0'.
+
+ TRY.
+ lv_date_int = ip_value.
+ IF lv_date_int NOT BETWEEN 1 AND 2958465.
+ ycx_ecb=>raise_text( 'Unable to interpret date' ).
+ ENDIF.
+ ep_value = lv_date_int + c_excel_baseline_date - 2.
+ " Needed hack caused by the problem that:
+ " Excel 2000 incorrectly assumes that the year 1900 is a leap year
+ " http://support.microsoft.com/kb/214326/en-us
+ IF ep_value < c_excel_1900_leap_year.
+ ep_value = ep_value + 1.
+ ENDIF.
+ CATCH cx_sy_conversion_error.
+ ycx_ecb=>raise_text( 'Index out of bounds' ).
+ ENDTRY.
+ ENDMETHOD.
+
+
+ METHOD excel_string_to_number.
+
+* If we encounter anything more complicated in EXCEL we might have to extend this
+* But currently this works fine - even for numbers in scientific notation
+
+ ep_value = ip_value.
+
+ ENDMETHOD.
+
+
+ METHOD excel_string_to_time.
+ DATA: lv_seconds_in_day TYPE i,
+ lv_day_fraction TYPE f,
+ lc_seconds_in_day TYPE i VALUE 86400.
+
+ TRY.
+
+ lv_day_fraction = ip_value.
+ lv_seconds_in_day = lv_day_fraction * lc_seconds_in_day.
+
+ ep_value = lv_seconds_in_day.
+
+ CATCH cx_sy_conversion_error.
+ ycx_ecb=>raise_text( 'Unable to interpret time' ).
+ ENDTRY.
+ ENDMETHOD.
+
+
+ METHOD get_fieldcatalog.
+ DATA: lr_dref_tab TYPE REF TO data,
+ lo_salv_table TYPE REF TO cl_salv_table,
+ lo_salv_columns_table TYPE REF TO cl_salv_columns_table,
+ lt_salv_t_column_ref TYPE salv_t_column_ref,
+ ls_salv_t_column_ref LIKE LINE OF lt_salv_t_column_ref,
+ lo_salv_column_table TYPE REF TO cl_salv_column_table.
+
+ FIELD-SYMBOLS: TYPE STANDARD TABLE.
+ FIELD-SYMBOLS: LIKE LINE OF ep_fieldcatalog.
+
+* Get copy of IP_TABLE-structure <-- must be changeable to create salv
+ CREATE DATA lr_dref_tab LIKE ip_table.
+ ASSIGN lr_dref_tab->* TO .
+* Create salv --> implicitly create fieldcat
+ TRY.
+ cl_salv_table=>factory( IMPORTING
+ r_salv_table = lo_salv_table
+ CHANGING
+ t_table = ).
+ lo_salv_columns_table = lo_salv_table->get_columns( ).
+ lt_salv_t_column_ref = lo_salv_columns_table->get( ).
+ CATCH cx_root.
+* maybe some errorhandling here - just haven't made up my mind yet
+ ENDTRY.
+
+* Loop through columns and set relevant fields ( fieldname, texts )
+ LOOP AT lt_salv_t_column_ref INTO ls_salv_t_column_ref.
+
+ lo_salv_column_table ?= ls_salv_t_column_ref-r_column.
+ APPEND INITIAL LINE TO ep_fieldcatalog ASSIGNING .
+ -position = sy-tabix.
+ -fieldname = ls_salv_t_column_ref-columnname.
+ -scrtext_s = ls_salv_t_column_ref-r_column->get_short_text( ).
+ -scrtext_m = ls_salv_t_column_ref-r_column->get_medium_text( ).
+ -scrtext_l = ls_salv_t_column_ref-r_column->get_long_text( ).
+ -currency_column = ls_salv_t_column_ref-r_column->get_currency_column( ).
+ " If currency column not in structure then clear the field again
+ IF -currency_column IS NOT INITIAL.
+ READ TABLE lt_salv_t_column_ref WITH KEY columnname = -currency_column TRANSPORTING NO FIELDS.
+ IF sy-subrc <> 0.
+ CLEAR -currency_column.
+ ENDIF.
+ ENDIF.
+
+ IF ip_conv_exit_length = abap_false.
+ -abap_type = lo_salv_column_table->get_ddic_inttype( ).
+ ENDIF.
+
+ -dynpfld = 'X'. " What in the world would we exclude here?
+ " except for the MANDT-field of most tables ( 1st column that is )
+ IF -position = 1 AND lo_salv_column_table->get_ddic_datatype( ) = 'CLNT' AND iv_hide_mandt = abap_true.
+ CLEAR -dynpfld.
+ ENDIF.
+
+* For fields that don't a description ( i.e. defined by "field type i," )
+* just use the fieldname as description - that is better than nothing
+ IF -scrtext_s IS INITIAL
+ AND -scrtext_m IS INITIAL
+ AND -scrtext_l IS INITIAL.
+ CONCATENATE 'Col:' -fieldname INTO -scrtext_l SEPARATED BY space.
+ -scrtext_m = -scrtext_l.
+ -scrtext_s = -scrtext_l.
+ ENDIF.
+
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+ METHOD is_cell_in_range.
+ DATA lv_column_start TYPE yecb_cell_column_alpha.
+ DATA lv_column_end TYPE yecb_cell_column_alpha.
+ DATA lv_row_start TYPE yecb_cell_row.
+ DATA lv_row_end TYPE yecb_cell_row.
+ DATA lv_column_start_i TYPE yecb_cell_column.
+ DATA lv_column_end_i TYPE yecb_cell_column.
+ DATA lv_column_i TYPE yecb_cell_column.
+
+
+* Split range and convert columns
+ convert_range2column_a_row(
+ EXPORTING
+ i_range = ip_range
+ IMPORTING
+ e_column_start = lv_column_start
+ e_column_end = lv_column_end
+ e_row_start = lv_row_start
+ e_row_end = lv_row_end ).
+
+ lv_column_start_i = convert_column2int( ip_column = lv_column_start ).
+ lv_column_end_i = convert_column2int( ip_column = lv_column_end ).
+
+ lv_column_i = convert_column2int( ip_column = ip_column ).
+
+* Check if cell is in range
+ IF lv_column_i >= lv_column_start_i AND
+ lv_column_i <= lv_column_end_i AND
+ ip_row >= lv_row_start AND
+ ip_row <= lv_row_end.
+ rp_in_range = abap_true.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD number_to_excel_string.
+ DATA: lv_value_c TYPE c LENGTH 100.
+
+ IF ip_currency IS INITIAL.
+ WRITE ip_value TO lv_value_c EXPONENT 0 NO-GROUPING NO-SIGN.
+ ELSE.
+ WRITE ip_value TO lv_value_c EXPONENT 0 NO-GROUPING NO-SIGN CURRENCY ip_currency.
+ ENDIF.
+ REPLACE ALL OCCURRENCES OF ',' IN lv_value_c WITH '.'.
+
+ ep_value = lv_value_c.
+ CONDENSE ep_value.
+
+ IF ip_value < 0.
+ CONCATENATE '-' ep_value INTO ep_value.
+ ELSEIF ip_value EQ 0.
+ ep_value = '0'.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD recursive_class_to_struct.
+ " # issue 139
+* is working for me - but after looking through this coding I guess
+* I'll rewrite this to a version w/o recursion
+* This is private an no one using it so far except me, so no need to hurry
+ DATA: descr TYPE REF TO cl_abap_structdescr,
+ wa_component LIKE LINE OF descr->components,
+ attribute_name LIKE wa_component-name,
+ flag_class TYPE abap_bool.
+
+ FIELD-SYMBOLS: TYPE any,
+ TYPE any,
+ TYPE any.
+
+
+ descr ?= cl_abap_structdescr=>describe_by_data( e_target ).
+
+ LOOP AT descr->components INTO wa_component.
+
+* Assign structure and X-structure
+ ASSIGN COMPONENT wa_component-name OF STRUCTURE e_target TO .
+ ASSIGN COMPONENT wa_component-name OF STRUCTURE e_targetx TO .
+* At least one field in the structure should be marked - otherwise continue with next field
+ CLEAR flag_class.
+* maybe source is just a structure - try assign component...
+ ASSIGN COMPONENT wa_component-name OF STRUCTURE i_source TO .
+ IF sy-subrc <> 0.
+* not - then it is an attribute of the class - use different assign then
+ CONCATENATE 'i_source->' wa_component-name INTO attribute_name.
+ ASSIGN (attribute_name) TO .
+ IF sy-subrc <> 0.
+ EXIT.
+ ENDIF. " Should not happen if structure is built properly - otherwise just exit to create no dumps
+ flag_class = abap_true.
+ ENDIF.
+
+ CASE wa_component-type_kind.
+ WHEN cl_abap_structdescr=>typekind_struct1 OR cl_abap_structdescr=>typekind_struct2. " Structure --> use recursio
+ ycl_ecb_common=>recursive_class_to_struct( EXPORTING i_source =
+ CHANGING e_target =
+ e_targetx = ).
+ WHEN OTHERS.
+ = .
+ = abap_true.
+
+ ENDCASE.
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+ METHOD recursive_struct_to_class.
+ " # issue 139
+* is working for me - but after looking through this coding I guess
+* I'll rewrite this to a version w/o recursion
+* This is private an no one using it so far except me, so no need to hurry
+ DATA: descr TYPE REF TO cl_abap_structdescr,
+ wa_component LIKE LINE OF descr->components,
+ attribute_name LIKE wa_component-name,
+ flag_class TYPE abap_bool,
+ o_border TYPE REF TO ycl_ecb_style_border.
+
+ FIELD-SYMBOLS: TYPE any,
+ TYPE any,
+ TYPE any.
+
+
+ descr ?= cl_abap_structdescr=>describe_by_data( i_source ).
+
+ LOOP AT descr->components INTO wa_component.
+
+* Assign structure and X-structure
+ ASSIGN COMPONENT wa_component-name OF STRUCTURE i_source TO .
+ ASSIGN COMPONENT wa_component-name OF STRUCTURE i_sourcex TO .
+* At least one field in the structure should be marked - otherwise continue with next field
+ CHECK CA abap_true.
+ CLEAR flag_class.
+* maybe target is just a structure - try assign component...
+ ASSIGN COMPONENT wa_component-name OF STRUCTURE e_target TO .
+ IF sy-subrc <> 0.
+* not - then it is an attribute of the class - use different assign then
+ CONCATENATE 'E_TARGET->' wa_component-name INTO attribute_name.
+ ASSIGN (attribute_name) TO .
+ IF sy-subrc <> 0.EXIT.ENDIF. " Should not happen if structure is built properly - otherwise just exit to create no dumps
+ flag_class = abap_true.
+ ENDIF.
+
+ CASE wa_component-type_kind.
+ WHEN cl_abap_structdescr=>typekind_struct1 OR cl_abap_structdescr=>typekind_struct2. " Structure --> use recursion
+ " To avoid dump with attribute GRADTYPE of class ZCL_EXCEL_STYLE_FILL
+ " quick and really dirty fix -> check the attribute name
+ " Border has to be initialized somewhere else
+ IF wa_component-name EQ 'GRADTYPE'.
+ flag_class = abap_false.
+ ENDIF.
+
+ IF flag_class = abap_true AND IS INITIAL.
+* Only borders will be passed as unbound references. But since we want to set a value we have to create an instance
+ CREATE OBJECT o_border.
+ = o_border.
+ ENDIF.
+ ycl_ecb_common=>recursive_struct_to_class( EXPORTING i_source =
+ i_sourcex =
+ CHANGING e_target = ).
+ WHEN OTHERS.
+ CHECK = abap_true. " Marked for change
+ = .
+
+ ENDCASE.
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+ METHOD shift_formula.
+
+ CONSTANTS: lcv_operators TYPE string VALUE '+-/*^%=<>&, !',
+ lcv_letters TYPE string VALUE 'ABCDEFGHIJKLMNOPQRSTUVWXYZ$',
+ lcv_digits TYPE string VALUE '0123456789',
+ lcv_cell_reference_error TYPE string VALUE '#REF!'.
+
+ DATA: lv_tcnt TYPE i, " Counter variable
+ lv_tlen TYPE i, " Temp variable length
+ lv_cnt TYPE i, " Counter variable
+ lv_cnt2 TYPE i, " Counter variable
+ lv_offset1 TYPE i, " Character offset
+ lv_numchars TYPE i, " Number of characters counter
+ lv_tchar(1) TYPE c, " Temp character
+ lv_tchar2(1) TYPE c, " Temp character
+ lv_cur_form TYPE string, " Formula for current cell
+ lv_ref_cell_addr TYPE string, " Reference cell address
+ lv_tcol1 TYPE string, " Temp column letter
+ lv_tcol2 TYPE string, " Temp column letter
+ lv_tcoln TYPE i, " Temp column number
+ lv_trow1 TYPE string, " Temp row number
+ lv_trow2 TYPE string, " Temp row number
+ lv_flen TYPE i, " Length of reference formula
+ lv_tlen2 TYPE i, " Temp variable length
+ lv_substr1 TYPE string, " Substring variable
+ lv_abscol TYPE string, " Absolute column symbol
+ lv_absrow TYPE string, " Absolute row symbol
+ lv_ref_formula TYPE string,
+ lv_compare_1 TYPE string,
+ lv_compare_2 TYPE string,
+ lv_level TYPE i, " Level of groups [..[..]..] or {..}
+
+ lv_errormessage TYPE string.
+
+*--------------------------------------------------------------------*
+* When copying a cell in EXCEL to another cell any inherent formulas
+* are copied as well. Cell-references in the formula are being adjusted
+* by the distance of the new cell to the original one
+*--------------------------------------------------------------------*
+* §1 Parse reference formula character by character
+* §2 Identify Cell-references
+* §3 Shift cell-reference
+* §4 Build resulting formula
+*--------------------------------------------------------------------*
+
+ lv_ref_formula = iv_reference_formula.
+*--------------------------------------------------------------------*
+* No distance --> Reference = resulting cell/formula
+*--------------------------------------------------------------------*
+ IF iv_shift_cols = 0
+ AND iv_shift_rows = 0.
+ ev_resulting_formula = lv_ref_formula.
+ RETURN. " done
+ ENDIF.
+
+
+ lv_flen = strlen( lv_ref_formula ).
+ lv_numchars = 1.
+
+*--------------------------------------------------------------------*
+* §1 Parse reference formula character by character
+*--------------------------------------------------------------------*
+ DO lv_flen TIMES.
+
+ CLEAR: lv_tchar,
+ lv_substr1,
+ lv_ref_cell_addr.
+ lv_cnt2 = lv_cnt + 1.
+ IF lv_cnt2 > lv_flen.
+ EXIT. " Done
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Here we have the current character in the formula
+*--------------------------------------------------------------------*
+ lv_tchar = lv_ref_formula+lv_cnt(1).
+
+*--------------------------------------------------------------------*
+* Operators or opening parenthesis will separate possible cellreferences
+*--------------------------------------------------------------------*
+ IF ( lv_tchar CA lcv_operators
+ OR lv_tchar CA '(' )
+ AND lv_cnt2 = 1.
+ lv_substr1 = lv_ref_formula+lv_offset1(1).
+ CONCATENATE lv_cur_form lv_substr1 INTO lv_cur_form.
+ lv_cnt = lv_cnt + 1.
+ lv_offset1 = lv_cnt.
+ lv_numchars = 1.
+ CONTINUE. " --> next character in formula can be analyzed
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Quoted literal text holds no cell reference --> advance to end of text
+*--------------------------------------------------------------------*
+ IF lv_tchar EQ '"'.
+ lv_cnt = lv_cnt + 1.
+ lv_numchars = lv_numchars + 1.
+ lv_tchar = lv_ref_formula+lv_cnt(1).
+ WHILE lv_tchar NE '"'.
+
+ lv_cnt = lv_cnt + 1.
+ lv_numchars = lv_numchars + 1.
+ lv_tchar = lv_ref_formula+lv_cnt(1).
+
+ ENDWHILE.
+ lv_cnt2 = lv_cnt + 1.
+ lv_substr1 = lv_ref_formula+lv_offset1(lv_numchars).
+ CONCATENATE lv_cur_form lv_substr1 INTO lv_cur_form.
+ lv_cnt = lv_cnt + 1.
+ IF lv_cnt = lv_flen.
+ EXIT.
+ ENDIF.
+ lv_offset1 = lv_cnt.
+ lv_numchars = 1.
+ lv_tchar = lv_ref_formula+lv_cnt(1).
+ lv_cnt2 = lv_cnt + 1.
+ CONTINUE. " --> next character in formula can be analyzed
+ ENDIF.
+
+
+*--------------------------------------------------------------------*
+* Groups - Ignore values inside blocks [..[..]..] and {..}
+* R1C1-Style Cell Reference: R[1]C[1]
+* Cell References: 'C:\[Source.xlsx]Sheet1'!$A$1
+* Array constants: {1,3.5,TRUE,"Hello"}
+* "Intra table reference": Flights[[#This Row],[Air fare]]
+*--------------------------------------------------------------------*
+ IF lv_tchar CA '[]{}' OR lv_level > 0.
+ IF lv_tchar CA '[{'.
+ lv_level = lv_level + 1.
+ ELSEIF lv_tchar CA ']}'.
+ lv_level = lv_level - 1.
+ ENDIF.
+ IF lv_cnt2 = lv_flen.
+ lv_substr1 = iv_reference_formula+lv_offset1(lv_numchars).
+ CONCATENATE lv_cur_form lv_substr1 INTO lv_cur_form.
+ EXIT.
+ ENDIF.
+ lv_numchars = lv_numchars + 1.
+ lv_cnt = lv_cnt + 1.
+ lv_cnt2 = lv_cnt + 1.
+ CONTINUE.
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Operators or parenthesis or last character in formula will separate possible cellreferences
+*--------------------------------------------------------------------*
+ IF lv_tchar CA lcv_operators
+ OR lv_tchar CA '():'
+ OR lv_cnt2 = lv_flen.
+ IF lv_cnt > 0.
+ lv_substr1 = lv_ref_formula+lv_offset1(lv_numchars).
+*--------------------------------------------------------------------*
+* Check for text concatenation and functions
+*--------------------------------------------------------------------*
+ IF ( lv_tchar CA lcv_operators AND lv_tchar EQ lv_substr1 ) OR lv_tchar EQ '('.
+ CONCATENATE lv_cur_form lv_substr1 INTO lv_cur_form.
+ lv_cnt = lv_cnt + 1.
+ lv_offset1 = lv_cnt.
+ lv_cnt2 = lv_cnt + 1.
+ lv_numchars = 1.
+ CONTINUE. " --> next character in formula can be analyzed
+ ENDIF.
+
+ lv_tlen = lv_cnt2 - lv_offset1.
+*--------------------------------------------------------------------*
+* Exclude mathematical operators and closing parentheses
+*--------------------------------------------------------------------*
+ IF lv_tchar CA lcv_operators
+ OR lv_tchar CA ':)'.
+ IF lv_cnt2 = lv_flen
+ AND lv_numchars = 1.
+ CONCATENATE lv_cur_form lv_substr1 INTO lv_cur_form.
+ lv_cnt = lv_cnt + 1.
+ lv_offset1 = lv_cnt.
+ lv_cnt2 = lv_cnt + 1.
+ lv_numchars = 1.
+ CONTINUE. " --> next character in formula can be analyzed
+ ELSE.
+ lv_tlen = lv_tlen - 1.
+ ENDIF.
+ ENDIF.
+*--------------------------------------------------------------------*
+* Capture reference cell address
+*--------------------------------------------------------------------*
+ TRY.
+ lv_ref_cell_addr = lv_ref_formula+lv_offset1(lv_tlen). "Ref cell address
+ CATCH cx_root.
+ lv_errormessage = 'Internal error in Class ZCL_EXCEL_COMMON Method SHIFT_FORMULA Spot 1 '. " Change to messageclass if possible
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDTRY.
+
+*--------------------------------------------------------------------*
+* Split cell address into characters and numbers
+*--------------------------------------------------------------------*
+ CLEAR: lv_tlen,
+ lv_tcnt,
+ lv_tcol1,
+ lv_trow1.
+ lv_tlen = strlen( lv_ref_cell_addr ).
+ IF lv_tlen <> 0.
+ CLEAR: lv_tcnt.
+ DO lv_tlen TIMES.
+ CLEAR: lv_tchar2.
+ lv_tchar2 = lv_ref_cell_addr+lv_tcnt(1).
+ IF lv_tchar2 CA lcv_letters.
+ CONCATENATE lv_tcol1 lv_tchar2 INTO lv_tcol1.
+ ELSEIF lv_tchar2 CA lcv_digits.
+ CONCATENATE lv_trow1 lv_tchar2 INTO lv_trow1.
+ ENDIF.
+ lv_tcnt = lv_tcnt + 1.
+ ENDDO.
+ ENDIF.
+
+ " Is valid column & row ?
+ IF lv_tcol1 IS NOT INITIAL AND lv_trow1 IS NOT INITIAL.
+ " COLUMN + ROW
+ CONCATENATE lv_tcol1 lv_trow1 INTO lv_compare_1.
+ " Original condensed string
+ lv_compare_2 = lv_ref_cell_addr.
+ CONDENSE lv_compare_2.
+ IF lv_compare_1 <> lv_compare_2.
+ CLEAR: lv_trow1, lv_tchar2.
+ ENDIF.
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Check for invalid cell address
+*--------------------------------------------------------------------*
+ IF lv_tcol1 IS INITIAL OR lv_trow1 IS INITIAL.
+ CONCATENATE lv_cur_form lv_substr1 INTO lv_cur_form.
+ lv_cnt = lv_cnt + 1.
+ lv_offset1 = lv_cnt.
+ lv_cnt2 = lv_cnt + 1.
+ lv_numchars = 1.
+ CONTINUE.
+ ENDIF.
+*--------------------------------------------------------------------*
+* Check for range names
+*--------------------------------------------------------------------*
+ CLEAR: lv_tlen.
+ lv_tlen = strlen( lv_tcol1 ).
+ IF lv_tlen GT 3.
+ CONCATENATE lv_cur_form lv_substr1 INTO lv_cur_form.
+ lv_cnt = lv_cnt + 1.
+ lv_offset1 = lv_cnt.
+ lv_cnt2 = lv_cnt + 1.
+ lv_numchars = 1.
+ CONTINUE.
+ ENDIF.
+*--------------------------------------------------------------------*
+* Check for valid row
+*--------------------------------------------------------------------*
+ IF lv_trow1 GT 1048576.
+ CONCATENATE lv_cur_form lv_substr1 INTO lv_cur_form.
+ lv_cnt = lv_cnt + 1.
+ lv_offset1 = lv_cnt.
+ lv_cnt2 = lv_cnt + 1.
+ lv_numchars = 1.
+ CONTINUE.
+ ENDIF.
+*--------------------------------------------------------------------*
+* Check for absolute column or row reference
+*--------------------------------------------------------------------*
+ CLEAR: lv_tcol2,
+ lv_trow2,
+ lv_abscol,
+ lv_absrow.
+ lv_tlen2 = strlen( lv_tcol1 ) - 1.
+ IF lv_tcol1 IS NOT INITIAL.
+ lv_abscol = lv_tcol1(1).
+ ENDIF.
+ IF lv_tlen2 GE 0.
+ lv_absrow = lv_tcol1+lv_tlen2(1).
+ ENDIF.
+ IF lv_abscol EQ '$' AND lv_absrow EQ '$'.
+ lv_tlen2 = lv_tlen2 - 1.
+ IF lv_tlen2 > 0.
+ lv_tcol1 = lv_tcol1+1(lv_tlen2).
+ ENDIF.
+ lv_tlen2 = lv_tlen2 + 1.
+ ELSEIF lv_abscol EQ '$'.
+ lv_tcol1 = lv_tcol1+1(lv_tlen2).
+ ELSEIF lv_absrow EQ '$'.
+ lv_tcol1 = lv_tcol1(lv_tlen2).
+ ENDIF.
+*--------------------------------------------------------------------*
+* Check for valid column
+*--------------------------------------------------------------------*
+ TRY.
+ lv_tcoln = ycl_ecb_common=>convert_column2int( lv_tcol1 ) + iv_shift_cols.
+ CATCH ycx_ecb.
+ CONCATENATE lv_cur_form lv_substr1 INTO lv_cur_form.
+ lv_cnt = lv_cnt + 1.
+ lv_offset1 = lv_cnt.
+ lv_cnt2 = lv_cnt + 1.
+ lv_numchars = 1.
+ CONTINUE.
+ ENDTRY.
+*--------------------------------------------------------------------*
+* Check whether there is a referencing problem
+*--------------------------------------------------------------------*
+ lv_trow2 = lv_trow1 + iv_shift_rows.
+ " Remove the space used for the sign
+ CONDENSE lv_trow2.
+ IF ( lv_tcoln < 1 AND lv_abscol <> '$' ) " Maybe we should add here max-column and max row-tests as well.
+ OR ( lv_trow2 < 1 AND lv_absrow <> '$' ). " Check how EXCEL behaves in this case
+*--------------------------------------------------------------------*
+* Referencing problem encountered --> set error
+*--------------------------------------------------------------------*
+ CONCATENATE lv_cur_form lcv_cell_reference_error INTO lv_cur_form.
+ ELSE.
+*--------------------------------------------------------------------*
+* No referencing problems --> adjust row and column
+*--------------------------------------------------------------------*
+
+*--------------------------------------------------------------------*
+* Adjust column
+*--------------------------------------------------------------------*
+ IF lv_abscol EQ '$'.
+ CONCATENATE lv_cur_form lv_abscol lv_tcol1 INTO lv_cur_form.
+ ELSEIF iv_shift_cols EQ 0.
+ CONCATENATE lv_cur_form lv_tcol1 INTO lv_cur_form.
+ ELSE.
+ TRY.
+ lv_tcol2 = ycl_ecb_common=>convert_column2alpha( lv_tcoln ).
+ CONCATENATE lv_cur_form lv_tcol2 INTO lv_cur_form.
+ CATCH ycx_ecb.
+ CONCATENATE lv_cur_form lv_substr1 INTO lv_cur_form.
+ lv_cnt = lv_cnt + 1.
+ lv_offset1 = lv_cnt.
+ lv_cnt2 = lv_cnt + 1.
+ lv_numchars = 1.
+ CONTINUE.
+ ENDTRY.
+ ENDIF.
+*--------------------------------------------------------------------*
+* Adjust row
+*--------------------------------------------------------------------*
+ IF lv_absrow EQ '$'.
+ CONCATENATE lv_cur_form lv_absrow lv_trow1 INTO lv_cur_form.
+ ELSEIF iv_shift_rows = 0.
+ CONCATENATE lv_cur_form lv_trow1 INTO lv_cur_form.
+ ELSE.
+ CONCATENATE lv_cur_form lv_trow2 INTO lv_cur_form.
+ ENDIF.
+ ENDIF.
+
+ lv_numchars = 0.
+ IF lv_tchar CA lcv_operators
+ OR lv_tchar CA ':)'.
+ CONCATENATE lv_cur_form lv_tchar INTO lv_cur_form RESPECTING BLANKS.
+ ENDIF.
+ lv_offset1 = lv_cnt2.
+ ENDIF.
+ ENDIF.
+ lv_numchars = lv_numchars + 1.
+ lv_cnt = lv_cnt + 1.
+ lv_cnt2 = lv_cnt + 1.
+
+ ENDDO.
+
+
+
+*--------------------------------------------------------------------*
+* Return resulting formula
+*--------------------------------------------------------------------*
+ IF lv_cur_form IS NOT INITIAL.
+ ev_resulting_formula = lv_cur_form.
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD shl01.
+
+ DATA:
+ lv_bit TYPE i,
+ lv_curr_pos TYPE i VALUE 2,
+ lv_prev_pos TYPE i VALUE 1.
+
+ DO 15 TIMES.
+ GET BIT lv_curr_pos OF i_pwd_hash INTO lv_bit.
+ SET BIT lv_prev_pos OF r_pwd_hash TO lv_bit.
+ ADD 1 TO lv_curr_pos.
+ ADD 1 TO lv_prev_pos.
+ ENDDO.
+ SET BIT 16 OF r_pwd_hash TO 0.
+
+ ENDMETHOD.
+
+
+ METHOD shr14.
+
+ DATA:
+ lv_bit TYPE i,
+ lv_curr_pos TYPE i,
+ lv_next_pos TYPE i.
+
+ r_pwd_hash = i_pwd_hash.
+
+ DO 14 TIMES.
+ lv_curr_pos = 15.
+ lv_next_pos = 16.
+
+ DO 15 TIMES.
+ GET BIT lv_curr_pos OF r_pwd_hash INTO lv_bit.
+ SET BIT lv_next_pos OF r_pwd_hash TO lv_bit.
+ SUBTRACT 1 FROM lv_curr_pos.
+ SUBTRACT 1 FROM lv_next_pos.
+ ENDDO.
+ SET BIT 1 OF r_pwd_hash TO 0.
+ ENDDO.
+
+ ENDMETHOD.
+
+
+ METHOD split_file.
+
+ DATA: lt_hlp TYPE TABLE OF text255,
+ ls_hlp TYPE text255.
+
+ DATA: lf_ext(10) TYPE c,
+ lf_dot_ext(10) TYPE c.
+ DATA: lf_anz TYPE i,
+ lf_len TYPE i.
+** ---------------------------------------------------------------------
+
+ CLEAR: lt_hlp,
+ ep_file,
+ ep_extension,
+ ep_dotextension.
+
+** Split the whole file at '.'
+ SPLIT ip_file AT '.' INTO TABLE lt_hlp.
+
+** get the extenstion from the last line of table
+ DESCRIBE TABLE lt_hlp LINES lf_anz.
+ IF lf_anz <= 1.
+ ep_file = ip_file.
+ RETURN.
+ ENDIF.
+
+ READ TABLE lt_hlp INTO ls_hlp INDEX lf_anz.
+ ep_extension = ls_hlp.
+ lf_ext = ls_hlp.
+ IF NOT lf_ext IS INITIAL.
+ CONCATENATE '.' lf_ext INTO lf_dot_ext.
+ ENDIF.
+ ep_dotextension = lf_dot_ext.
+
+** get only the filename
+ lf_len = strlen( ip_file ) - strlen( lf_dot_ext ).
+ IF lf_len > 0.
+ ep_file = ip_file(lf_len).
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD structure_case.
+ DATA: lt_comp_str TYPE abap_component_tab.
+
+ CASE is_component-type->kind.
+ WHEN cl_abap_typedescr=>kind_elem. "E Elementary Type
+ INSERT is_component INTO TABLE xt_components.
+ WHEN cl_abap_typedescr=>kind_table. "T Table
+ INSERT is_component INTO TABLE xt_components.
+ WHEN cl_abap_typedescr=>kind_struct. "S Structure
+ lt_comp_str = structure_recursive( is_component = is_component ).
+ INSERT LINES OF lt_comp_str INTO TABLE xt_components.
+ WHEN OTHERS. "cl_abap_typedescr=>kind_ref or cl_abap_typedescr=>kind_class or cl_abap_typedescr=>kind_intf.
+* We skip it. for now.
+ ENDCASE.
+ ENDMETHOD.
+
+
+ METHOD structure_recursive.
+ DATA: lo_struct TYPE REF TO cl_abap_structdescr,
+ lt_components TYPE abap_component_tab,
+ ls_components TYPE abap_componentdescr.
+
+ lo_struct ?= is_component-type.
+ lt_components = lo_struct->get_components( ).
+
+ LOOP AT lt_components INTO ls_components.
+ structure_case( EXPORTING is_component = ls_components
+ CHANGING xt_components = rt_components ) .
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+ METHOD time_to_excel_string.
+ DATA: lv_seconds_in_day TYPE i,
+ lv_day_fraction TYPE f,
+ lc_time_baseline TYPE t VALUE '000000',
+ lc_seconds_in_day TYPE i VALUE 86400.
+
+ lv_seconds_in_day = ip_value - lc_time_baseline.
+ lv_day_fraction = lv_seconds_in_day / lc_seconds_in_day.
+ ep_value = ycl_ecb_common=>number_to_excel_string( ip_value = lv_day_fraction ).
+ ENDMETHOD.
+
+
+ METHOD unescape_string.
+
+ CONSTANTS lcv_regex TYPE string VALUE `^'[^']` & `|` & " Beginning single ' OR
+ `[^']'$` & `|` & " Trailing single ' OR
+ `[^']'[^']`. " Single ' somewhere in between
+
+
+ DATA: lv_errormessage TYPE string. " Can't pass '...'(abc) to exception-class
+
+*--------------------------------------------------------------------*
+* This method is used to extract the "real" string from an escaped string.
+* An escaped string can be identified by a beginning ' which must be
+* accompanied by a trailing '
+* All '' in between beginning and trailing ' are treated as single '
+*--------------------------------------------------------------------*
+
+*--------------------------------------------------------------------*
+* When allowing clike-input parameters we might encounter trailing
+* "real" blanks . These are automatically eliminated when moving
+* the input parameter to a string.
+*--------------------------------------------------------------------*
+ ev_unescaped_string = iv_escaped. " Pass through if not escaped
+
+ CHECK ev_unescaped_string IS NOT INITIAL. " Nothing to do if empty
+ CHECK ev_unescaped_string(1) = `'`. " Nothing to do if not escaped
+
+*--------------------------------------------------------------------*
+* Remove leading and trailing '
+*--------------------------------------------------------------------*
+ REPLACE REGEX `^'(.*)'$` IN ev_unescaped_string WITH '$1'.
+ IF sy-subrc <> 0.
+ lv_errormessage = 'Input not properly escaped - &'(002).
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Any remaining single ' should not be here
+*--------------------------------------------------------------------*
+ FIND REGEX lcv_regex IN ev_unescaped_string.
+ IF sy-subrc = 0.
+ lv_errormessage = 'Input not properly escaped - &'(002).
+ ycx_ecb=>raise_text( lv_errormessage ).
+ ENDIF.
+
+*--------------------------------------------------------------------*
+* Replace '' with '
+*--------------------------------------------------------------------*
+ REPLACE ALL OCCURRENCES OF `''` IN ev_unescaped_string WITH `'`.
+
+
+ ENDMETHOD.
+
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_common.clas.testclasses.abap b/src/abap2xlsx/ycl_ecb_common.clas.testclasses.abap
new file mode 100644
index 0000000..93d8f21
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_common.clas.testclasses.abap
@@ -0,0 +1,1734 @@
+CLASS lcl_excel_common_test DEFINITION DEFERRED.
+CLASS ycl_ecb_common DEFINITION LOCAL FRIENDS lcl_excel_common_test.
+
+*----------------------------------------------------------------------*
+* CLASS lcl_Excel_Common_Test DEFINITION
+*----------------------------------------------------------------------*
+*
+*----------------------------------------------------------------------*
+CLASS lcl_excel_common_test DEFINITION FOR TESTING
+ RISK LEVEL HARMLESS
+ DURATION SHORT.
+
+ PRIVATE SECTION.
+* ================
+ TYPES: BEGIN OF ty_convert_range2column_a_row,
+ column_start TYPE yecb_cell_column_alpha,
+ column_start_int TYPE yecb_cell_column,
+ column_end TYPE yecb_cell_column_alpha,
+ column_end_int TYPE yecb_cell_column,
+ row_start TYPE yecb_cell_row,
+ row_end TYPE yecb_cell_row,
+ sheet TYPE string,
+ END OF ty_convert_range2column_a_row.
+ DATA:
+ lx_excel TYPE REF TO ycx_ecb,
+ ls_symsg_act LIKE sy, " actual messageinformation of exception
+ ls_symsg_exp LIKE sy, " expected messageinformation of exception
+ f_cut TYPE REF TO ycl_ecb_common. "class under test
+
+ METHODS: setup.
+ METHODS: convert_column2alpha_simple FOR TESTING.
+ METHODS: convert_column2alpha_maxcol FOR TESTING.
+ METHODS: convert_column2alpha_last FOR TESTING.
+ METHODS: convert_column2alpha_oob FOR TESTING.
+ METHODS convert_column2int_basic FOR TESTING.
+ METHODS convert_column2int_from_int FOR TESTING RAISING cx_static_check.
+ METHODS convert_column2int_maxcol FOR TESTING.
+ METHODS convert_column2int_oob_empty FOR TESTING.
+ METHODS convert_column2int_oob_invalid FOR TESTING.
+ METHODS convert_column_a_row2columnrow FOR TESTING RAISING cx_static_check.
+ METHODS convert_columnrow2column_a_row FOR TESTING RAISING cx_static_check.
+ METHODS date_to_excel_string1 FOR TESTING RAISING cx_static_check.
+ METHODS date_to_excel_string2 FOR TESTING RAISING cx_static_check.
+ METHODS date_to_excel_string3 FOR TESTING RAISING cx_static_check.
+ METHODS date_to_excel_string4 FOR TESTING RAISING cx_static_check.
+ METHODS date_to_excel_string5 FOR TESTING RAISING cx_static_check.
+ METHODS date_to_excel_string6 FOR TESTING RAISING cx_static_check.
+ METHODS amount_to_excel_string1 FOR TESTING RAISING cx_static_check.
+ METHODS amount_to_excel_string2 FOR TESTING RAISING cx_static_check.
+ METHODS amount_to_excel_string3 FOR TESTING RAISING cx_static_check.
+ METHODS: encrypt_password FOR TESTING.
+ METHODS: excel_string_to_date FOR TESTING.
+ METHODS excel_string_to_time1 FOR TESTING RAISING cx_static_check.
+ METHODS excel_string_to_time2 FOR TESTING RAISING cx_static_check.
+ METHODS excel_string_to_time3 FOR TESTING RAISING cx_static_check.
+ METHODS excel_string_to_time4 FOR TESTING RAISING cx_static_check.
+ METHODS excel_string_to_time5 FOR TESTING RAISING cx_static_check.
+ METHODS time_to_excel_string1 FOR TESTING RAISING cx_static_check.
+ METHODS time_to_excel_string2 FOR TESTING RAISING cx_static_check.
+ METHODS time_to_excel_string3 FOR TESTING RAISING cx_static_check.
+ METHODS time_to_excel_string4 FOR TESTING RAISING cx_static_check.
+ METHODS: split_file FOR TESTING.
+ METHODS: convert_range2column_a_row FOR TESTING RAISING cx_static_check.
+ METHODS: assert_convert_range2column_a_
+ IMPORTING
+ i_range TYPE clike
+ i_allow_1dim_range TYPE abap_bool DEFAULT abap_false
+ is_exp TYPE ty_convert_range2column_a_row
+ RAISING
+ cx_static_check.
+ METHODS: describe_structure FOR TESTING.
+ METHODS macro_calculate_cell_distance
+ IMPORTING
+ iv_reference_cell TYPE clike
+ iv_current_cell TYPE clike
+ iv_expected_column TYPE i
+ iv_expected_row TYPE i
+ RAISING
+ cx_static_check.
+ METHODS: calc_cell_dist_samecell FOR TESTING RAISING cx_static_check,
+ calc_cell_dist_down1pl FOR TESTING RAISING cx_static_check,
+ calc_cell_dist_downsome FOR TESTING RAISING cx_static_check,
+ calc_cell_dist_up1pl FOR TESTING RAISING cx_static_check,
+ calc_cell_dist_upsome FOR TESTING RAISING cx_static_check,
+ calc_cell_dist_right1pl FOR TESTING RAISING cx_static_check,
+ calc_cell_dist_rightsome FOR TESTING RAISING cx_static_check,
+ calc_cell_dist_left1pl FOR TESTING RAISING cx_static_check,
+ calc_cell_dist_leftsome FOR TESTING RAISING cx_static_check,
+ calc_cell_dist_fullpack FOR TESTING RAISING cx_static_check.
+ METHODS macro_shift_formula
+ IMPORTING
+ iv_reference_formula TYPE clike
+ iv_shift_cols TYPE i
+ iv_shift_rows TYPE i
+ iv_expected TYPE string.
+ METHODS: shift_formula_basic FOR TESTING,
+ shift_formula_rightdown FOR TESTING,
+ shift_formula_leftup FOR TESTING,
+ shift_formula_fixedcolrows FOR TESTING,
+ shift_formula_mixedfixedrows FOR TESTING,
+ shift_formula_rangename FOR TESTING,
+ shift_formula_stringlitconc FOR TESTING,
+ shift_formula_extref FOR TESTING,
+ shift_formula_charblanks FOR TESTING,
+ shift_formula_stringblanks FOR TESTING,
+ shift_formula_funcnoargs FOR TESTING,
+ shift_formula_nocellref FOR TESTING,
+ shift_formula_empty FOR TESTING,
+ shift_formula_referr_colunder FOR TESTING,
+ shift_formula_referr_rowunder FOR TESTING,
+ shift_formula_referr_rowcolund FOR TESTING,
+ shift_formula_sheet_nodigit FOR TESTING,
+ shift_formula_sheet_nodig FOR TESTING,
+ shift_formula_sheet_special FOR TESTING,
+ shift_formula_resp_blanks_1 FOR TESTING,
+ shift_formula_resp_blanks_2 FOR TESTING,
+ shift_formula_range FOR TESTING,
+ shift_formula_notcols FOR TESTING,
+ shift_formula_name FOR TESTING,
+ shift_formula_refcolumn1 FOR TESTING,
+ shift_formula_refcolumn2 FOR TESTING.
+ METHODS is_cell_in_range_ulc_in FOR TESTING.
+ METHODS is_cell_in_range_lrc_in FOR TESTING.
+ METHODS is_cell_in_range_leftside_out FOR TESTING.
+ METHODS is_cell_in_range_upperside_out FOR TESTING.
+ METHODS is_cell_in_range_rightside_out FOR TESTING.
+ METHODS is_cell_in_range_lowerside_out FOR TESTING.
+ METHODS escape_string_whitespace1 FOR TESTING.
+ METHODS escape_string_whitespace2 FOR TESTING.
+ METHODS escape_string_whitespace3 FOR TESTING.
+ METHODS escape_string_quote FOR TESTING.
+ METHODS escape_string_hyphen FOR TESTING.
+ METHODS escape_string_regular FOR TESTING.
+ENDCLASS.
+
+
+*----------------------------------------------------------------------*
+* CLASS lcl_Excel_Common_Test IMPLEMENTATION
+*----------------------------------------------------------------------*
+*
+*----------------------------------------------------------------------*
+CLASS lcl_excel_common_test IMPLEMENTATION.
+* ===========================================
+
+ METHOD setup.
+* =============
+
+ CREATE OBJECT f_cut.
+ ENDMETHOD. "setup
+
+
+ METHOD convert_column2alpha_simple.
+* ============================
+ DATA ep_column TYPE yecb_cell_column_alpha.
+
+* Test 1. Simple test
+ TRY.
+ ep_column = ycl_ecb_common=>convert_column2alpha( 1 ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_column
+ exp = 'A'
+ msg = 'Wrong column conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+ ENDMETHOD. "convert_column2alpha_simple
+
+
+ METHOD convert_column2alpha_maxcol.
+* ============================
+ DATA ep_column TYPE yecb_cell_column_alpha.
+
+* Test 2. Max column for OXML #16,384 = XFD
+ TRY.
+ ep_column = ycl_ecb_common=>convert_column2alpha( 16384 ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_column
+ exp = 'XFD'
+ msg = 'Wrong column conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+ ENDMETHOD. "convert_column2alpha_maxcol
+
+
+ METHOD convert_column2alpha_last.
+* ============================
+ DATA ep_column TYPE yecb_cell_column_alpha.
+
+* Test 3. Index 0 is out of bounds
+ TRY.
+ ep_column = ycl_ecb_common=>convert_column2alpha( 0 ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_column
+ exp = 'A'
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>assert_equals(
+ act = lx_excel->error
+ exp = 'Index out of bounds'
+ msg = 'Colum index 0 is out of bounds, min column index is 1'
+ level = if_aunit_constants=>fatal
+ ).
+ ENDTRY.
+ ENDMETHOD. "convert_column2alpha_last
+
+
+ METHOD convert_column2alpha_oob.
+* ============================
+ DATA ep_column TYPE yecb_cell_column_alpha.
+
+* Test 4. Exception should be thrown index out of bounds
+ TRY.
+ ep_column = ycl_ecb_common=>convert_column2alpha( 16385 ).
+
+ cl_abap_unit_assert=>assert_differs(
+ act = ep_column
+ exp = 'XFE'
+ msg = 'Colum index 16385 is out of bounds, max column index is 16384'
+ level = if_aunit_constants=>fatal
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>assert_equals(
+ act = lx_excel->error
+ exp = 'Index out of bounds'
+ msg = 'Wrong exception is thrown'
+ level = if_aunit_constants=>tolerable
+ ).
+ ENDTRY.
+ ENDMETHOD. "convert_Column2alpha_oob
+
+
+ METHOD convert_column2int_basic.
+* ==========================
+* Test 1. Basic test
+ DATA ep_column TYPE yecb_cell_column.
+
+ TRY.
+ ep_column = ycl_ecb_common=>convert_column2int( 'A' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_column
+ exp = 1
+ msg = 'Wrong column conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+ ENDMETHOD. "convert_column2int_basic.
+
+
+ METHOD convert_column2int_from_int.
+
+ DATA ep_column TYPE yecb_cell_column.
+
+ ep_column = ycl_ecb_common=>convert_column2int( 5 ).
+
+ cl_abap_unit_assert=>assert_equals( act = ep_column exp = 5 ).
+
+ ENDMETHOD.
+
+
+ METHOD convert_column2int_maxcol.
+* ==========================
+* Test 2. Max column
+ DATA ep_column TYPE yecb_cell_column.
+
+ TRY.
+ ep_column = ycl_ecb_common=>convert_column2int( 'XFD' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_column
+ exp = 16384
+ msg = 'Wrong column conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+ ENDMETHOD. "convert_column2int_maxcol
+
+
+ METHOD convert_column2int_oob_empty.
+* ==========================
+* Test 3. Out of bounds
+ DATA ep_column TYPE yecb_cell_column.
+
+ TRY.
+ ep_column = ycl_ecb_common=>convert_column2int( '' ).
+
+ cl_abap_unit_assert=>assert_differs( act = ep_column
+ exp = '0'
+ msg = 'Wrong column conversion'
+ level = if_aunit_constants=>critical ).
+ CATCH ycx_ecb INTO lx_excel.
+ CLEAR: ls_symsg_act,
+ ls_symsg_exp.
+ ls_symsg_exp-msgid = 'ZABAP2XLSX'.
+ ls_symsg_exp-msgno = '800'.
+ ls_symsg_act-msgid = lx_excel->syst_at_raise-msgid.
+ ls_symsg_act-msgno = lx_excel->syst_at_raise-msgno.
+ cl_abap_unit_assert=>assert_equals( act = ls_symsg_act
+ exp = ls_symsg_exp
+ msg = 'Colum name should be a valid string'
+ level = if_aunit_constants=>fatal ).
+ ENDTRY.
+ ENDMETHOD. "convert_column2int_oob_empty.
+
+
+ METHOD convert_column2int_oob_invalid.
+* ==========================
+* Test 4. Out of bounds
+ DATA ep_column TYPE yecb_cell_column.
+
+ TRY.
+ ep_column = ycl_ecb_common=>convert_column2int( 'XFE' ).
+
+ cl_abap_unit_assert=>assert_differs( act = ep_column
+ exp = 16385
+ msg = 'Wrong column conversion'
+ level = if_aunit_constants=>critical ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>assert_equals( act = lx_excel->error
+ exp = 'Index out of bounds'
+ msg = 'Colum XFE is out of range'
+ level = if_aunit_constants=>fatal ).
+ ENDTRY.
+ ENDMETHOD. "convert_column2int_oob_invalid.
+
+
+ METHOD convert_column_a_row2columnrow.
+
+ DATA: cell_coords TYPE string.
+
+ cell_coords = ycl_ecb_common=>convert_column_a_row2columnrow( i_column = 'B' i_row = 6 ).
+
+ cl_abap_unit_assert=>assert_equals( act = cell_coords exp = 'B6' ).
+
+
+ cell_coords = ycl_ecb_common=>convert_column_a_row2columnrow( i_column = 2 i_row = 6 ).
+
+ cl_abap_unit_assert=>assert_equals( act = cell_coords exp = 'B6' ).
+
+ ENDMETHOD.
+
+
+ METHOD convert_columnrow2column_a_row.
+
+ DATA: column TYPE yecb_cell_column_alpha,
+ column_int TYPE yecb_cell_column,
+ row TYPE yecb_cell_row.
+
+ ycl_ecb_common=>convert_columnrow2column_a_row(
+ EXPORTING
+ i_columnrow = 'B6'
+ IMPORTING
+ e_column = column
+ e_column_int = column_int
+ e_row = row ).
+
+ cl_abap_unit_assert=>assert_equals( act = column exp = 'B' msg = 'Invalid column (alpha)' ).
+ cl_abap_unit_assert=>assert_equals( act = column_int exp = 2 msg = 'Invalid column (numeric)' ).
+ cl_abap_unit_assert=>assert_equals( act = row exp = 6 msg = 'Invalid row' ).
+
+ ENDMETHOD.
+
+
+ METHOD date_to_excel_string1.
+ DATA ep_value TYPE yecb_cell_value.
+
+* Test 1. Basic conversion
+ ep_value = ycl_ecb_common=>date_to_excel_string( '19000101' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = 1
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD date_to_excel_string2.
+ DATA ep_value TYPE yecb_cell_value.
+
+* Check around the "Excel Leap Year" 1900
+ ep_value = ycl_ecb_common=>date_to_excel_string( '19000228' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = 59
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD date_to_excel_string3.
+ DATA ep_value TYPE yecb_cell_value.
+
+ ep_value = ycl_ecb_common=>date_to_excel_string( '19000301' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = 61
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD date_to_excel_string4.
+ DATA ep_value TYPE yecb_cell_value.
+
+* Test 2. Basic conversion
+ ep_value = ycl_ecb_common=>date_to_excel_string( '99991212' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = 2958446
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD date_to_excel_string5.
+ DATA ep_value TYPE yecb_cell_value.
+
+* Test 3. Initial date
+ DATA: lv_date TYPE d.
+ ep_value = ycl_ecb_common=>date_to_excel_string( lv_date ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = ''
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD date_to_excel_string6.
+ DATA ep_value TYPE yecb_cell_value.
+
+* Test 2. Basic conversion
+ DATA exp_value TYPE yecb_cell_value VALUE 0.
+ ep_value = ycl_ecb_common=>date_to_excel_string( '18991231' ).
+
+ cl_abap_unit_assert=>assert_differs(
+ act = ep_value
+ exp = exp_value
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD amount_to_excel_string1.
+ DATA ep_value TYPE yecb_cell_value.
+
+ ep_value = ycl_ecb_common=>number_to_excel_string( ip_value = '1003.99'
+ ip_currency = 'EUR' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '1003.99'
+ msg = 'Wrong currency amount conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD amount_to_excel_string2.
+ DATA ep_value TYPE yecb_cell_value.
+
+ ep_value = ycl_ecb_common=>number_to_excel_string( ip_value = '-1003.99'
+ ip_currency = 'HUF' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '-100399'
+ msg = 'Wrong currency amount conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD amount_to_excel_string3.
+ DATA ep_value TYPE yecb_cell_value.
+
+ ep_value = ycl_ecb_common=>number_to_excel_string( ip_value = '0'
+ ip_currency = 'HUF' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '0'
+ msg = 'Wrong currency amount conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD encrypt_password.
+* ========================
+ DATA lv_encrypted_pwd TYPE yecb_aes_password.
+
+ TRY.
+ lv_encrypted_pwd = ycl_ecb_common=>encrypt_password( 'test' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = lv_encrypted_pwd
+ exp = 'CBEB'
+ msg = 'Wrong password encryption'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+ ENDMETHOD. "encrypt_Password
+
+
+ METHOD excel_string_to_date.
+* ============================
+ DATA ep_value TYPE d.
+
+
+* Test 1. Simple test -> ABAP Manage also date prior of 1900
+ TRY.
+ ep_value = ycl_ecb_common=>excel_string_to_date( '0' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '00000000'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+* Check empty content
+ TRY.
+ ep_value = ycl_ecb_common=>excel_string_to_date( '' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '00000000'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+* Check space character
+ TRY.
+ ep_value = ycl_ecb_common=>excel_string_to_date( ` ` ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '00000000'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+* Check first Excel date 1/1/1900
+ TRY.
+ ep_value = ycl_ecb_common=>excel_string_to_date( '1' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '19000101'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+* Check around the "Excel Leap Year" 1900
+ TRY.
+ ep_value = ycl_ecb_common=>excel_string_to_date( '59' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '19000228'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+ TRY.
+ ep_value = ycl_ecb_common=>excel_string_to_date( '61' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '19000301'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+
+* Test 2. Simple test
+ TRY.
+ ep_value = ycl_ecb_common=>excel_string_to_date( '1' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '19000101'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+
+* Test 3. Last possible date
+ TRY.
+ ep_value = ycl_ecb_common=>excel_string_to_date( '2958465' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '99991231'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical
+ ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>fail(
+ msg = 'unexpected exception'
+ level = if_aunit_constants=>critical " Error Severity
+ ).
+ ENDTRY.
+
+* Test 4. Exception should be thrown index out of bounds
+ TRY.
+ ep_value = ycl_ecb_common=>excel_string_to_date( '2958466' ).
+
+ cl_abap_unit_assert=>fail(
+ msg = |Unexpected result '{ ep_value }'|
+ level = if_aunit_constants=>critical
+ ).
+
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>assert_equals(
+ act = lx_excel->error
+ exp = 'Unable to interpret date'
+ msg = 'Time should be a valid date'
+ level = if_aunit_constants=>fatal
+ ).
+ ENDTRY.
+ ENDMETHOD. "excel_String_To_Date
+
+
+ METHOD excel_string_to_time1.
+ DATA ep_value TYPE t.
+
+* Test 1. Simple test
+ ep_value = ycl_ecb_common=>excel_string_to_time( '0' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '000000'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>tolerable ).
+
+ ENDMETHOD.
+
+ METHOD excel_string_to_time2.
+ DATA ep_value TYPE t.
+* Test 2. Simple test
+
+ ep_value = ycl_ecb_common=>excel_string_to_time( '1' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '000000'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD excel_string_to_time3.
+ DATA ep_value TYPE t.
+* Test 3. Simple test
+
+ ep_value = ycl_ecb_common=>excel_string_to_time( '0.99999' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '235959'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD excel_string_to_time4.
+ DATA ep_value TYPE t.
+* Test 4. Also string greater than 1 should be managed
+
+ ep_value = ycl_ecb_common=>excel_string_to_time( '4.1' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '022400'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD excel_string_to_time5.
+ DATA ep_value TYPE t.
+* Test 4. string is not a number
+ TRY.
+ ep_value = ycl_ecb_common=>excel_string_to_time( 'NaN' ).
+
+ cl_abap_unit_assert=>assert_differs(
+ act = ep_value
+ exp = '000000'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+ CATCH ycx_ecb INTO lx_excel.
+ cl_abap_unit_assert=>assert_equals(
+ act = lx_excel->error
+ exp = 'Unable to interpret time'
+ msg = 'Time should be a valid string'
+ level = if_aunit_constants=>fatal ).
+ ENDTRY.
+ ENDMETHOD.
+
+ METHOD time_to_excel_string1.
+ DATA ep_value TYPE yecb_cell_value.
+
+* Test 1. Basic conversion
+ ep_value = ycl_ecb_common=>time_to_excel_string( '000001' ).
+ " A test directly in Excel returns the value 0.0000115740740740741000
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '0.0000115740740741'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD time_to_excel_string2.
+ DATA ep_value TYPE yecb_cell_value.
+
+* Test 2. Basic conversion
+ ep_value = ycl_ecb_common=>time_to_excel_string( '235959' ).
+ " A test directly in Excel returns the value 0.9999884259259260000000
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '0.9999884259259260'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD time_to_excel_string3.
+ DATA ep_value TYPE yecb_cell_value.
+
+* Test 3. Initial date
+ ep_value = ycl_ecb_common=>time_to_excel_string( '000000' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '0'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD time_to_excel_string4.
+
+ DATA ep_value TYPE yecb_cell_value.
+
+* Test 2. Basic conversion
+ ep_value = ycl_ecb_common=>time_to_excel_string( '022400' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_value
+ exp = '0.1000000000000000'
+ msg = 'Wrong date conversion'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD split_file.
+* ============================
+
+ DATA: ep_file TYPE text255,
+ ep_extension TYPE char10,
+ ep_dotextension TYPE char10.
+
+
+* Test 1. Basic conversion
+ ycl_ecb_common=>split_file( EXPORTING ip_file = 'filename.xml'
+ IMPORTING ep_file = ep_file
+ ep_extension = ep_extension
+ ep_dotextension = ep_dotextension ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_file
+ exp = 'filename'
+ msg = 'Split filename failed'
+ level = if_aunit_constants=>critical ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_extension
+ exp = 'xml'
+ msg = 'Split extension failed'
+ level = if_aunit_constants=>critical ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_dotextension
+ exp = '.xml'
+ msg = 'Split extension failed'
+ level = if_aunit_constants=>critical ).
+
+* Test 2. no extension
+ ycl_ecb_common=>split_file( EXPORTING ip_file = 'filename'
+ IMPORTING ep_file = ep_file
+ ep_extension = ep_extension
+ ep_dotextension = ep_dotextension ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_file
+ exp = 'filename'
+ msg = 'Split filename failed'
+ level = if_aunit_constants=>critical ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_extension
+ exp = ''
+ msg = 'Split extension failed'
+ level = if_aunit_constants=>critical ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_dotextension
+ exp = ''
+ msg = 'Split extension failed'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD. "split_file
+
+ METHOD convert_range2column_a_row.
+ DATA: lv_range TYPE string,
+ ls_exp TYPE ty_convert_range2column_a_row.
+
+* a) input empty --> nothing to do
+ lv_range = ''.
+
+ CLEAR ls_exp.
+
+ assert_convert_range2column_a_( i_range = lv_range is_exp = ls_exp ).
+
+* b) sheetname existing - starts with ' example 'Sheet 1'!$B$6:$D$13
+ lv_range = `'Sheet 1'!$B$6:$D$13`.
+
+ CLEAR ls_exp.
+ ls_exp-column_start = 'B'.
+ ls_exp-column_start_int = 2.
+ ls_exp-column_end = 'D'.
+ ls_exp-column_end_int = 4.
+ ls_exp-row_start = 6.
+ ls_exp-row_end = 13.
+ ls_exp-sheet = 'Sheet 1'.
+
+ assert_convert_range2column_a_( i_range = lv_range is_exp = ls_exp ).
+
+* c) sheetname existing - does not start with ' example Sheet1!$B$6:$D$13
+ lv_range = `Sheet1!B6:$D$13`.
+
+ CLEAR ls_exp.
+ ls_exp-column_start = 'B'.
+ ls_exp-column_start_int = 2.
+ ls_exp-column_end = 'D'.
+ ls_exp-column_end_int = 4.
+ ls_exp-row_start = 6.
+ ls_exp-row_end = 13.
+ ls_exp-sheet = 'Sheet1'.
+
+ assert_convert_range2column_a_( i_range = lv_range is_exp = ls_exp ).
+
+* d) no sheetname - just area example $B$6:$D$13
+ lv_range = `$B$6:D13`.
+
+ CLEAR ls_exp.
+ ls_exp-column_start = 'B'.
+ ls_exp-column_start_int = 2.
+ ls_exp-column_end = 'D'.
+ ls_exp-column_end_int = 4.
+ ls_exp-row_start = 6.
+ ls_exp-row_end = 13.
+
+ assert_convert_range2column_a_( i_range = lv_range is_exp = ls_exp ).
+
+**********************************************************************
+* 1 Dimensional Ranges - Ros or Cols Only (eg Print Tiles)
+*
+ lv_range = `$2:$7`.
+
+ CLEAR ls_exp.
+
+ assert_convert_range2column_a_( i_range = lv_range i_allow_1dim_range = abap_false is_exp = ls_exp ).
+
+***
+ lv_range = `$2:$7`.
+
+ CLEAR ls_exp.
+ ls_exp-row_start = 2.
+ ls_exp-row_end = 7.
+
+ assert_convert_range2column_a_( i_range = lv_range i_allow_1dim_range = abap_true is_exp = ls_exp ).
+
+***
+ lv_range = `Sheet3!$D:$I`.
+
+ CLEAR ls_exp.
+ ls_exp-column_start = 'D'.
+ ls_exp-column_start_int = 4.
+ ls_exp-column_end = 'I'.
+ ls_exp-column_end_int = 9.
+ ls_exp-sheet = 'Sheet3'.
+
+ assert_convert_range2column_a_( i_range = lv_range i_allow_1dim_range = abap_true is_exp = ls_exp ).
+
+ ENDMETHOD. "convert_range2column_a_row
+
+
+ METHOD assert_convert_range2column_a_.
+
+ DATA: ls_act TYPE ty_convert_range2column_a_row,
+ lv_message TYPE string.
+
+ ycl_ecb_common=>convert_range2column_a_row(
+ EXPORTING
+ i_range = i_range
+ i_allow_1dim_range = i_allow_1dim_range
+ IMPORTING
+ e_column_start = ls_act-column_start
+ e_column_start_int = ls_act-column_start_int
+ e_column_end = ls_act-column_end
+ e_column_end_int = ls_act-column_end_int
+ e_row_start = ls_act-row_start
+ e_row_end = ls_act-row_end
+ e_sheet = ls_act-sheet ).
+
+ lv_message = `Invalid column start (alpha) for ` && i_range.
+ cl_abap_unit_assert=>assert_equals(
+ act = ls_act-column_start
+ exp = is_exp-column_start
+ msg = lv_message ).
+ lv_message = `Invalid column start (numeric) for ` && i_range.
+ cl_abap_unit_assert=>assert_equals(
+ act = ls_act-column_start_int
+ exp = is_exp-column_start_int
+ msg = lv_message ).
+ lv_message = `Invalid column end (alpha) for ` && i_range.
+ cl_abap_unit_assert=>assert_equals(
+ act = ls_act-column_end
+ exp = is_exp-column_end
+ msg = lv_message ).
+ lv_message = `Invalid column end (numeric) for ` && i_range.
+ cl_abap_unit_assert=>assert_equals(
+ act = ls_act-column_end_int
+ exp = is_exp-column_end_int
+ msg = lv_message ).
+ lv_message = `Invalid row start for ` && i_range.
+ cl_abap_unit_assert=>assert_equals(
+ act = ls_act-row_start
+ exp = is_exp-row_start
+ msg = lv_message ).
+ lv_message = `Invalid row end for ` && i_range.
+ cl_abap_unit_assert=>assert_equals(
+ act = ls_act-row_end
+ exp = is_exp-row_end
+ msg = lv_message ).
+ lv_message = `Invalid sheet for ` && i_range.
+ cl_abap_unit_assert=>assert_equals(
+ act = ls_act-sheet
+ exp = is_exp-sheet
+ msg = lv_message ).
+
+ ENDMETHOD.
+
+
+ METHOD describe_structure.
+ DATA: ls_test TYPE yecb_pane.
+ DATA: lo_structdescr TYPE REF TO cl_abap_structdescr.
+ DATA: lt_structure TYPE ddfields.
+ FIELD-SYMBOLS: LIKE LINE OF lt_structure.
+
+ " Test with DDIC Type
+ lo_structdescr ?= cl_abap_structdescr=>describe_by_data( p_data = ls_test ).
+ lt_structure = ycl_ecb_common=>describe_structure( io_struct = lo_structdescr ).
+ READ TABLE lt_structure ASSIGNING INDEX 1.
+ cl_abap_unit_assert=>assert_equals(
+ act = -fieldname
+ exp = 'YSPLIT'
+ msg = 'Describe structure failed'
+ level = if_aunit_constants=>critical ).
+
+ " Test with local defined structure having DDIC and non DDIC elements
+ TYPES:
+ BEGIN OF t_test,
+ carrid TYPE string,
+ carrname TYPE string,
+ carrdesc TYPE string,
+ END OF t_test.
+ DATA: ls_ttest TYPE t_test.
+
+ lo_structdescr ?= cl_abap_structdescr=>describe_by_data( p_data = ls_ttest ).
+ lt_structure = ycl_ecb_common=>describe_structure( io_struct = lo_structdescr ).
+ READ TABLE lt_structure ASSIGNING INDEX 1.
+ cl_abap_unit_assert=>assert_equals(
+ act = -fieldname
+ exp = 'CARRID'
+ msg = 'Describe structure failed'
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD. "describe_structure
+
+ METHOD macro_calculate_cell_distance.
+
+ DATA: lv_offset_rows TYPE i,
+ lv_offset_cols TYPE i,
+ lv_message TYPE string.
+
+ ycl_ecb_common=>calculate_cell_distance( EXPORTING iv_reference_cell = iv_reference_cell
+ iv_current_cell = iv_current_cell
+ IMPORTING ev_row_difference = lv_offset_rows
+ ev_col_difference = lv_offset_cols ).
+* Check delta columns
+ CONCATENATE 'Error calculating column difference in test:'
+ iv_reference_cell
+ '->'
+ iv_current_cell
+ INTO lv_message SEPARATED BY space.
+ cl_abap_unit_assert=>assert_equals( act = lv_offset_cols
+ exp = iv_expected_column
+ msg = lv_message
+ quit = 0 " continue tests
+ level = if_aunit_constants=>critical ).
+* Check delta rows
+ CONCATENATE 'Error calculating row difference in test:'
+ iv_reference_cell
+ '->'
+ iv_current_cell
+ INTO lv_message SEPARATED BY space.
+ cl_abap_unit_assert=>assert_equals( act = lv_offset_rows
+ exp = iv_expected_row
+ msg = lv_message
+ quit = 0 " continue tests
+ level = if_aunit_constants=>critical ).
+
+ ENDMETHOD.
+
+ METHOD calc_cell_dist_samecell.
+
+ " Same cell
+ macro_calculate_cell_distance(
+ iv_reference_cell = 'C12'
+ iv_current_cell = 'C12'
+ iv_expected_column = 0
+ iv_expected_row = 0 ).
+ ENDMETHOD.
+
+ METHOD calc_cell_dist_down1pl.
+
+ " Shift down 1 place
+ macro_calculate_cell_distance(
+ iv_reference_cell = 'C12'
+ iv_current_cell = 'C13'
+ iv_expected_column = 0
+ iv_expected_row = 1 ).
+ ENDMETHOD.
+
+ METHOD calc_cell_dist_downsome.
+
+ " Shift down some places
+ macro_calculate_cell_distance(
+ iv_reference_cell = 'C12'
+ iv_current_cell = 'C25'
+ iv_expected_column = 0
+ iv_expected_row = 13 ).
+ ENDMETHOD.
+
+ METHOD calc_cell_dist_up1pl.
+
+ " Shift up 1 place
+ macro_calculate_cell_distance(
+ iv_reference_cell = 'C12'
+ iv_current_cell = 'C11'
+ iv_expected_column = 0
+ iv_expected_row = -1 ).
+ ENDMETHOD.
+
+ METHOD calc_cell_dist_upsome.
+
+ " Shift up some place
+ macro_calculate_cell_distance(
+ iv_reference_cell = 'C12'
+ iv_current_cell = 'C1'
+ iv_expected_column = 0
+ iv_expected_row = -11 ).
+ ENDMETHOD.
+
+ METHOD calc_cell_dist_right1pl.
+
+ " Shift right 1 place
+ macro_calculate_cell_distance(
+ iv_reference_cell = 'C12'
+ iv_current_cell = 'D12'
+ iv_expected_column = 1
+ iv_expected_row = 0 ).
+ ENDMETHOD.
+
+ METHOD calc_cell_dist_rightsome.
+
+ " Shift right some places
+ macro_calculate_cell_distance(
+ iv_reference_cell = 'C12'
+ iv_current_cell = 'AA12'
+ iv_expected_column = 24
+ iv_expected_row = 0 ).
+ ENDMETHOD.
+
+ METHOD calc_cell_dist_left1pl.
+
+ " Shift left 1 place
+ macro_calculate_cell_distance(
+ iv_reference_cell = 'C12'
+ iv_current_cell = 'B12'
+ iv_expected_column = -1
+ iv_expected_row = 0 ).
+ ENDMETHOD.
+
+ METHOD calc_cell_dist_leftsome.
+
+ " Shift left some place
+ macro_calculate_cell_distance(
+ iv_reference_cell = 'AA12'
+ iv_current_cell = 'C12'
+ iv_expected_column = -24
+ iv_expected_row = 0 ).
+ ENDMETHOD.
+
+ METHOD calc_cell_dist_fullpack.
+
+ " The full package.
+ macro_calculate_cell_distance(
+ iv_reference_cell = 'AA121'
+ iv_current_cell = 'C12'
+ iv_expected_column = -24
+ iv_expected_row = -109 ).
+ ENDMETHOD.
+
+ METHOD macro_shift_formula.
+
+ DATA: lv_resulting_formula TYPE string,
+ lv_message TYPE string,
+ lv_counter TYPE n LENGTH 8.
+
+ ADD 1 TO lv_counter.
+ CLEAR lv_resulting_formula.
+ TRY.
+ lv_resulting_formula = ycl_ecb_common=>shift_formula( iv_reference_formula = iv_reference_formula
+ iv_shift_cols = iv_shift_cols
+ iv_shift_rows = iv_shift_rows ).
+ CONCATENATE 'Wrong result in test'
+ lv_counter
+ 'shifting formula '
+ iv_reference_formula
+ INTO lv_message SEPARATED BY space.
+ cl_abap_unit_assert=>assert_equals( act = lv_resulting_formula
+ exp = iv_expected
+ msg = lv_message
+ quit = 0 " continue tests
+ level = if_aunit_constants=>critical ).
+ CATCH ycx_ecb.
+ CONCATENATE 'Unexpected exception occurred in test'
+ lv_counter
+ 'shifting formula '
+ iv_reference_formula
+ INTO lv_message SEPARATED BY space.
+ cl_abap_unit_assert=>assert_equals( act = lv_resulting_formula
+ exp = iv_expected
+ msg = lv_message
+ quit = 0 " continue tests
+ level = if_aunit_constants=>critical ).
+ ENDTRY.
+
+ ENDMETHOD.
+
+ METHOD shift_formula_basic.
+
+ " Very basic check
+ macro_shift_formula(
+ iv_reference_formula = 'C17'
+ iv_shift_cols = 0
+ iv_shift_rows = 0
+ iv_expected = 'C17' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_rightdown.
+
+ " Check shift right and down
+ macro_shift_formula(
+ iv_reference_formula = 'C17'
+ iv_shift_cols = 2
+ iv_shift_rows = 3
+ iv_expected = 'E20' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_leftup.
+
+ " Check shift left and up
+ macro_shift_formula(
+ iv_reference_formula = 'C17'
+ iv_shift_cols = -2
+ iv_shift_rows = -3
+ iv_expected = 'A14' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_fixedcolrows.
+
+ " Fixed columns/rows
+ macro_shift_formula(
+ iv_reference_formula = '$C$17'
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = '$C$17' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_mixedfixedrows.
+
+ " Operators and Ranges, mixed fixed rows or columns
+ macro_shift_formula(
+ iv_reference_formula = 'SUM($C17:C$23)+C30'
+ iv_shift_cols = 1
+ iv_shift_rows = 11
+ iv_expected = 'SUM($C28:D$23)+D41' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_rangename.
+
+ " Operators and Rangename
+ macro_shift_formula(
+ iv_reference_formula = 'RNGNAME1+C7'
+ iv_shift_cols = -1
+ iv_shift_rows = -4
+ iv_expected = 'RNGNAME1+B3' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_stringlitconc.
+
+ " String literals and string concatenation
+ macro_shift_formula(
+ iv_reference_formula = '"Date:"&TEXT(B2)'
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = '"Date:"&TEXT(C3)' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_extref.
+
+ " External sheet reference
+ macro_shift_formula(
+ iv_reference_formula = '[TEST6.XLSX]SHEET1!A1'
+ iv_shift_cols = 1
+ iv_shift_rows = 11
+ iv_expected = '[TEST6.XLSX]SHEET1!B12' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_charblanks.
+
+ " superflous blanks, multi-argument functions, literals in function, unknown functions
+ macro_shift_formula(
+ iv_reference_formula = `X(B13, "KK" ) `
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = `X(C14, "KK" ) ` ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_stringblanks.
+
+ " same as above - but with string input instead of Char-input
+ macro_shift_formula(
+ iv_reference_formula = `SIN(SIN(SIN(SIN(E22))))`
+ iv_shift_cols = 0
+ iv_shift_rows = 1
+ iv_expected = 'SIN(SIN(SIN(SIN(E23))))' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_funcnoargs.
+
+ " Functions w/o arguments, No cellreferences
+ macro_shift_formula(
+ iv_reference_formula = 'HEUTE()'
+ iv_shift_cols = 2
+ iv_shift_rows = 5
+ iv_expected = 'HEUTE()' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_nocellref.
+
+ " No cellreferences
+ macro_shift_formula(
+ iv_reference_formula = '"B2"'
+ iv_shift_cols = 2
+ iv_shift_rows = 5
+ iv_expected = '"B2"' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_empty.
+
+ " Empty
+ macro_shift_formula(
+ iv_reference_formula = ''
+ iv_shift_cols = 2
+ iv_shift_rows = 5
+ iv_expected = '' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_referr_colunder.
+
+ " Referencing error , column only , underflow
+ macro_shift_formula(
+ iv_reference_formula = 'A1+$A1+A$1+$A$1+B2'
+ iv_shift_cols = -1
+ iv_shift_rows = 0
+ iv_expected = '#REF!+$A1+#REF!+$A$1+A2' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_referr_rowunder.
+
+ " Referencing error , row only , underflow
+ macro_shift_formula(
+ iv_reference_formula = 'A1+$A1+A$1+$A$1+B2'
+ iv_shift_cols = 0
+ iv_shift_rows = -1
+ iv_expected = '#REF!+#REF!+A$1+$A$1+B1' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_referr_rowcolund.
+
+ " Referencing error , row and column , underflow
+ macro_shift_formula(
+ iv_reference_formula = 'A1+$A1+A$1+$A$1+B2'
+ iv_shift_cols = -1
+ iv_shift_rows = -1
+ iv_expected = '#REF!+#REF!+#REF!+$A$1+A1' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_sheet_nodigit.
+
+ " Sheet name not ending with digit
+ macro_shift_formula(
+ iv_reference_formula = 'Sheet!A1'
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = 'Sheet!B2' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_sheet_nodig.
+
+ " Sheet name ending with digit
+ macro_shift_formula(
+ iv_reference_formula = 'Sheet2!A1'
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = 'Sheet2!B2' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_sheet_special.
+
+ " Sheet name with special characters
+ macro_shift_formula(
+ iv_reference_formula = |'Sheet name'!A1|
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = |'Sheet name'!B2| ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_resp_blanks_1.
+
+ " Respecting blanks
+ macro_shift_formula(
+ iv_reference_formula = 'SUBTOTAL(109,Table1[SUM 1])'
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = 'SUBTOTAL(109,Table1[SUM 1])' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_resp_blanks_2.
+
+ " Respecting blanks
+ macro_shift_formula(
+ iv_reference_formula = 'B4 & C4'
+ iv_shift_cols = 0
+ iv_shift_rows = 1
+ iv_expected = 'B5 & C5' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_range.
+
+ " F_1 is a range name, not a cell address
+ macro_shift_formula(
+ iv_reference_formula = 'SUM(F_1,F_2)'
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = 'SUM(F_1,F_2)' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_notcols.
+ " RC are not columns
+ macro_shift_formula(
+ iv_reference_formula = 'INDIRECT("RC[4]",FALSE)'
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = 'INDIRECT("RC[4]",FALSE)' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_name.
+
+ " A1 is a sheet name
+ macro_shift_formula(
+ iv_reference_formula = |'A1'!$A$1|
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = |'A1'!$A$1| ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_refcolumn1.
+
+ " Reference to another column in the same row of a Table, with a space in the column name
+ macro_shift_formula(
+ iv_reference_formula = 'Tbl[[#This Row],[Air fare]]'
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = 'Tbl[[#This Row],[Air fare]]' ).
+
+ ENDMETHOD.
+
+ METHOD shift_formula_refcolumn2.
+
+ " Reference to another column in the same row of a Table, inside more complex expression
+ macro_shift_formula(
+ iv_reference_formula = 'Tbl[[#This Row],[Air]]+A1'
+ iv_shift_cols = 1
+ iv_shift_rows = 1
+ iv_expected = 'Tbl[[#This Row],[Air]]+B2' ).
+
+ ENDMETHOD.
+
+ METHOD is_cell_in_range_ulc_in.
+* Test 1: upper left corner (in range)
+ DATA ep_cell_in_range TYPE abap_bool.
+
+ TRY.
+ ep_cell_in_range = ycl_ecb_common=>is_cell_in_range(
+ ip_column = 'B'
+ ip_row = 2
+ ip_range = 'B2:D4' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_cell_in_range
+ exp = abap_true
+ msg = 'Check cell in range failed'
+ level = if_aunit_constants=>critical ).
+ CATCH ycx_ecb.
+ cl_abap_unit_assert=>fail(
+ msg = 'Unexpected exception'
+ level = if_aunit_constants=>critical ).
+ ENDTRY.
+ ENDMETHOD. "is_cell_in_range_ulc_in
+
+ METHOD is_cell_in_range_lrc_in.
+* Test 2: lower right corner (in range)
+ DATA ep_cell_in_range TYPE abap_bool.
+
+ TRY.
+ ep_cell_in_range = ycl_ecb_common=>is_cell_in_range(
+ ip_column = 'D'
+ ip_row = 4
+ ip_range = 'B2:D4' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_cell_in_range
+ exp = abap_true
+ msg = 'Check cell in range failed'
+ level = if_aunit_constants=>critical ).
+ CATCH ycx_ecb.
+ cl_abap_unit_assert=>fail(
+ msg = 'Unexpected exception'
+ level = if_aunit_constants=>critical ).
+ ENDTRY.
+ ENDMETHOD. "is_cell_in_range_lrc_in
+
+ METHOD is_cell_in_range_leftside_out.
+* Test 3: left side (out of range)
+ DATA ep_cell_in_range TYPE abap_bool.
+
+ TRY.
+ ep_cell_in_range = ycl_ecb_common=>is_cell_in_range(
+ ip_column = 'A'
+ ip_row = 3
+ ip_range = 'B2:D4' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_cell_in_range
+ exp = abap_false
+ msg = 'Check cell in range failed'
+ level = if_aunit_constants=>critical ).
+ CATCH ycx_ecb.
+ cl_abap_unit_assert=>fail(
+ msg = 'Unexpected exception'
+ level = if_aunit_constants=>critical ).
+ ENDTRY.
+ ENDMETHOD. "is_cell_in_range_leftside_out
+
+ METHOD is_cell_in_range_upperside_out.
+* Test 4: upper side (out of range)
+ DATA ep_cell_in_range TYPE abap_bool.
+
+ TRY.
+ ep_cell_in_range = ycl_ecb_common=>is_cell_in_range(
+ ip_column = 'C'
+ ip_row = 1
+ ip_range = 'B2:D4' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_cell_in_range
+ exp = abap_false
+ msg = 'Check cell in range failed'
+ level = if_aunit_constants=>critical ).
+ CATCH ycx_ecb.
+ cl_abap_unit_assert=>fail(
+ msg = 'Unexpected exception'
+ level = if_aunit_constants=>critical ).
+ ENDTRY.
+ ENDMETHOD. "is_cell_in_range_upperside_out
+
+ METHOD is_cell_in_range_rightside_out.
+* Test 5: right side (out of range)
+ DATA ep_cell_in_range TYPE abap_bool.
+
+ TRY.
+ ep_cell_in_range = ycl_ecb_common=>is_cell_in_range(
+ ip_column = 'E'
+ ip_row = 3
+ ip_range = 'B2:D4' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_cell_in_range
+ exp = abap_false
+ msg = 'Check cell in range failed'
+ level = if_aunit_constants=>critical ).
+ CATCH ycx_ecb.
+ cl_abap_unit_assert=>fail(
+ msg = 'Unexpected exception'
+ level = if_aunit_constants=>critical ).
+ ENDTRY.
+ ENDMETHOD. "is_cell_in_range_rightside_out
+
+ METHOD is_cell_in_range_lowerside_out.
+* Test 6: lower side (out of range)
+ DATA ep_cell_in_range TYPE abap_bool.
+
+ TRY.
+ ep_cell_in_range = ycl_ecb_common=>is_cell_in_range(
+ ip_column = 'C'
+ ip_row = 5
+ ip_range = 'B2:D4' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ act = ep_cell_in_range
+ exp = abap_false
+ msg = 'Check cell in range failed'
+ level = if_aunit_constants=>critical ).
+ CATCH ycx_ecb.
+ cl_abap_unit_assert=>fail(
+ msg = 'Unexpected exception'
+ level = if_aunit_constants=>critical ).
+ ENDTRY.
+ ENDMETHOD. "is_cell_in_range_lowerside_out.
+
+ METHOD escape_string_hyphen.
+ DATA: name TYPE string,
+ escaped_name TYPE string.
+
+ name = `A-B`.
+
+ escaped_name = ycl_ecb_common=>escape_string( name ).
+
+ cl_abap_unit_assert=>assert_equals( act = escaped_name
+ exp = `'A-B'`
+ msg = 'Escaping - failed' ).
+
+ ENDMETHOD.
+
+ METHOD escape_string_quote.
+ DATA: name TYPE string,
+ escaped_name TYPE string.
+
+ name = `A'B`.
+
+ escaped_name = ycl_ecb_common=>escape_string( name ).
+
+ cl_abap_unit_assert=>assert_equals( act = escaped_name
+ exp = `'A''B'`
+ msg = `Escaping ' failed` ).
+
+ ENDMETHOD.
+
+ METHOD escape_string_regular.
+ DATA: name TYPE string,
+ escaped_name TYPE string.
+
+ name = `Ab1`.
+
+ escaped_name = ycl_ecb_common=>escape_string( name ).
+
+ cl_abap_unit_assert=>assert_equals( act = escaped_name
+ exp = `Ab1`
+ msg = 'Escaped for no reason' ).
+
+ ENDMETHOD.
+
+ METHOD escape_string_whitespace1.
+ DATA: name TYPE string,
+ escaped_name TYPE string.
+
+ name = `A B`.
+
+ escaped_name = ycl_ecb_common=>escape_string( name ).
+
+ cl_abap_unit_assert=>assert_equals( act = escaped_name
+ exp = `'A B'`
+ msg = `Escaping ' ' (space) failed` ).
+
+ ENDMETHOD.
+
+ METHOD escape_string_whitespace2.
+ DATA: name TYPE string,
+ escaped_name TYPE string.
+
+ name = `A` && cl_abap_char_utilities=>horizontal_tab && `B`.
+
+ escaped_name = ycl_ecb_common=>escape_string( name ).
+
+ cl_abap_unit_assert=>assert_equals( act = escaped_name
+ exp = `'A` && cl_abap_char_utilities=>horizontal_tab && `B'`
+ msg = `Escaping TAB failed` ).
+
+ ENDMETHOD.
+
+ METHOD escape_string_whitespace3.
+ DATA: name TYPE string,
+ escaped_name TYPE string.
+
+ name = `A` && cl_abap_char_utilities=>newline && `B`.
+
+ escaped_name = ycl_ecb_common=>escape_string( name ).
+
+ cl_abap_unit_assert=>assert_equals( act = escaped_name
+ exp = `'A` && cl_abap_char_utilities=>newline && `B'`
+ msg = `Escaping LF failed` ).
+
+ ENDMETHOD.
+
+ENDCLASS.
diff --git a/src/abap2xlsx/ycl_ecb_common.clas.xml b/src/abap2xlsx/ycl_ecb_common.clas.xml
new file mode 100644
index 0000000..bf58be6
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_common.clas.xml
@@ -0,0 +1,406 @@
+
+
+
+
+
+ YCL_ECB_COMMON
+ E
+ Static common methods
+ 1
+ X
+ X
+ X
+ X
+
+
+ -
+ I
+ 001
+ Invalid range
+ 60
+
+ -
+ I
+ 002
+ Input not properly escaped - &
+ 60
+
+ -
+ I
+ 003
+ Unable to interpret input as column
+ 60
+
+ -
+ I
+ 004
+ Index out of bounds
+ 60
+
+ -
+ I
+ 005
+ Excel Workbook (*.xlsx)|*.xlsx|
+ 80
+
+
+
+
+ CALCULATE_CELL_DISTANCE
+ E
+ Give distance between two cells
+
+
+ CALCULATE_CELL_DISTANCE
+ I
+ Give distance between two cells
+
+
+ CHAR2HEX
+ E
+ Character to Hexadecimal
+
+
+ CHAR2HEX
+ I
+ Character to Hexadecimal
+
+
+ CLASS_CONSTRUCTOR
+ E
+ CLASS_CONSTRUCTOR
+
+
+ CONVERT_COLUMN2ALPHA
+ E
+ Convert column indicator to Alpha
+
+
+ CONVERT_COLUMN2ALPHA
+ I
+ Convert column indicator to Alpha
+
+
+ CONVERT_COLUMN2INT
+ E
+ Convert column indicator to Integer
+
+
+ CONVERT_COLUMN2INT
+ I
+ Convert column indicator to Integer
+
+
+ CONVERT_COLUMNROW2COLUMN_A_ROW
+ E
+ Convert ColumnRow i.e. AB34 to AB and 34
+
+
+ CONVERT_COLUMNROW2COLUMN_A_ROW
+ I
+ Convert ColumnRow i.e. AB34 to AB and 34
+
+
+ CONVERT_RANGE2COLUMN_A_ROW
+ E
+ Converts Sheet1!AB34:CD56 to Sheet1, AB, 34, CD, 56
+
+
+ CONVERT_RANGE2COLUMN_A_ROW
+ I
+ Converts Sheet1!AB34:CD56 to Sheet1, AB, 34, CD, 56
+
+
+ C_EXCEL_1900_LEAP_YEAR
+ E
+ Excel baseline date
+
+
+ C_EXCEL_1900_LEAP_YEAR
+ I
+ Excel baseline date
+
+
+ C_EXCEL_BASELINE_DATE
+ E
+ Excel baseline date
+
+
+ C_EXCEL_BASELINE_DATE
+ I
+ Excel baseline date
+
+
+ C_EXCEL_COL_MODULE
+ E
+ 2 byte integer (signed)
+
+
+ C_EXCEL_COL_MODULE
+ I
+ 2 byte integer (signed)
+
+
+ C_EXCEL_NUMFMT_OFFSET
+ E
+ 2 byte integer (signed)
+
+
+ C_EXCEL_NUMFMT_OFFSET
+ I
+ 2 byte integer (signed)
+
+
+ C_EXCEL_SHEET_MAX_COL
+ E
+ 2 byte integer (signed)
+
+
+ C_EXCEL_SHEET_MAX_COL
+ I
+ 2 byte integer (signed)
+
+
+ C_EXCEL_SHEET_MAX_ROW
+ E
+ 2 byte integer (signed)
+
+
+ C_EXCEL_SHEET_MIN_COL
+ E
+ 2 byte integer (signed)
+
+
+ C_EXCEL_SHEET_MIN_COL
+ I
+ 2 byte integer (signed)
+
+
+ C_EXCEL_SHEET_MIN_ROW
+ E
+ 2 byte integer (signed)
+
+
+ C_SPRAS_EN
+ E
+ Language Key
+
+
+ C_SPRAS_EN
+ I
+ Language Key
+
+
+ C_XLSX_FILE_FILTER
+ E
+ File filter
+
+
+ C_XLSX_FILE_FILTER
+ I
+ File filter
+
+
+ DATE_TO_EXCEL_STRING
+ E
+ Convert date from SAP format to Excel
+
+
+ DATE_TO_EXCEL_STRING
+ I
+ Convert date from SAP format to Excel
+
+
+ DESCRIBE_STRUCTURE
+ E
+ Describe database info of structure
+
+
+ DESCRIBE_STRUCTURE
+ I
+ Describe database info of structure
+
+
+ DETERMINE_RESULTING_FORMULA
+ E
+ Determine formula if copied to another cell
+
+
+ DETERMINE_RESULTING_FORMULA
+ I
+ Determine formula if copied to another cell
+
+
+ ENCRYPT_PASSWORD
+ E
+ Encrypt password
+
+
+ ENCRYPT_PASSWORD
+ I
+ Encrypt password
+
+
+ ESCAPE_STRING
+ E
+ Escape a string
+
+
+ ESCAPE_STRING
+ I
+ Escape a string
+
+
+ EXCEL_STRING_TO_DATE
+ E
+ Convert date from Excel format to SAP
+
+
+ EXCEL_STRING_TO_DATE
+ I
+ Convert date from Excel format to SAP
+
+
+ EXCEL_STRING_TO_NUMBER
+ E
+ Convert number from Excel format to SAP
+
+
+ EXCEL_STRING_TO_TIME
+ E
+ Convert time from Excel format to SAP
+
+
+ EXCEL_STRING_TO_TIME
+ I
+ Convert time from Excel format to SAP
+
+
+ GET_FIELDCATALOG
+ E
+ Creates field catalog for BIND_TABLE based on internal table
+
+
+ GET_FIELDCATALOG
+ I
+ Creates field catalog for BIND_TABLE based on internal table
+
+
+ IS_CELL_IN_RANGE
+ E
+ Check if cell is part of a range
+
+
+ NUMBER_TO_EXCEL_STRING
+ E
+ Converts number to string representation in Excel format
+
+
+ NUMBER_TO_EXCEL_STRING
+ I
+ Converts number to string representation in Excel format
+
+
+ O_CONV
+ E
+ Code Page and Endian Conversion (System Format -> External)
+
+
+ O_CONV
+ I
+ Code Page and Endian Conversion (System Format -> External)
+
+
+ RECURSIVE_CLASS_TO_STRUCT
+ E
+ Move class to structure
+
+
+ RECURSIVE_CLASS_TO_STRUCT
+ I
+ Move class to structure
+
+
+ RECURSIVE_STRUCT_TO_CLASS
+ E
+ Move structure to class
+
+
+ RECURSIVE_STRUCT_TO_CLASS
+ I
+ Move structure to class
+
+
+ SHIFT_FORMULA
+ E
+ Shift formula from one cell to another
+
+
+ SHIFT_FORMULA
+ I
+ Shift formula from one cell to another
+
+
+ SHL01
+ E
+ Secret function
+
+
+ SHR14
+ E
+ Secret function
+
+
+ SPLIT_FILE
+ E
+ File & Extension disconnect (clone of FM CV120_SPLIT_FILE)
+
+
+ SPLIT_FILE
+ I
+ File & Extension disconnect (clone of FM CV120_SPLIT_FILE)
+
+
+ STRUCTURE_CASE
+ E
+ Case stement for recursive
+
+
+ STRUCTURE_CASE
+ I
+ Case stement for recursive
+
+
+ STRUCTURE_RECURSIVE
+ E
+ Get structure details
+
+
+ STRUCTURE_RECURSIVE
+ I
+ Get structure details
+
+
+ TIME_TO_EXCEL_STRING
+ E
+ Convert time from SAP format to Excel
+
+
+ TIME_TO_EXCEL_STRING
+ I
+ Convert time from SAP format to Excel
+
+
+ UNESCAPE_STRING
+ E
+ Unescape
+
+
+ UNESCAPE_STRING
+ I
+ Unescape
+
+
+
+
+
diff --git a/src/abap2xlsx/ycl_ecb_converter.clas.abap b/src/abap2xlsx/ycl_ecb_converter.clas.abap
new file mode 100644
index 0000000..807ced5
--- /dev/null
+++ b/src/abap2xlsx/ycl_ecb_converter.clas.abap
@@ -0,0 +1,1817 @@
+CLASS ycl_ecb_converter DEFINITION
+ PUBLIC
+ CREATE PUBLIC .
+
+*"* public components of class ZCL_EXCEL_CONVERTER
+*"* do not include other source files here!!!
+ PUBLIC SECTION.
+
+ CLASS-METHODS class_constructor .
+ METHODS ask_option
+ RETURNING
+ VALUE(rs_option) TYPE yecb_s_converter_option
+ RAISING
+ ycx_ecb .
+ METHODS convert
+ IMPORTING
+ !is_option TYPE yecb_s_converter_option OPTIONAL
+ !io_alv TYPE REF TO object OPTIONAL
+ !it_table TYPE STANDARD TABLE OPTIONAL
+ !i_row_int TYPE i DEFAULT 1
+ !i_column_int TYPE i DEFAULT 1
+ !i_table TYPE flag OPTIONAL
+ !i_style_table TYPE yecb_table_style OPTIONAL
+ !io_worksheet TYPE REF TO ycl_ecb_worksheet OPTIONAL
+ CHANGING
+ !co_excel TYPE REF TO ycl_ecb OPTIONAL
+ RAISING
+ ycx_ecb .
+ METHODS create_path
+ RETURNING
+ VALUE(r_path) TYPE string .
+ METHODS get_file
+ EXPORTING
+ !e_bytecount TYPE i
+ !et_file TYPE solix_tab
+ !e_file TYPE xstring
+ RAISING
+ ycx_ecb .
+ METHODS get_option
+ RETURNING
+ VALUE(rs_option) TYPE yecb_s_converter_option .
+ METHODS open_file
+ RAISING
+ ycx_ecb .
+ METHODS set_option
+ IMPORTING
+ !is_option TYPE yecb_s_converter_option .
+ METHODS write_file
+ IMPORTING
+ !i_path TYPE string OPTIONAL
+ RAISING
+ ycx_ecb .
+*"* protected components of class ZCL_EXCEL_CONVERTER
+*"* do not include other source files here!!!
+ PROTECTED SECTION.
+
+ TYPES:
+ BEGIN OF t_relationship,
+ id TYPE string,
+ type TYPE string,
+ target TYPE string,
+ END OF t_relationship .
+ TYPES:
+ BEGIN OF t_fileversion,
+ appname TYPE string,
+ lastedited TYPE string,
+ lowestedited TYPE string,
+ rupbuild TYPE string,
+ codename TYPE string,
+ END OF t_fileversion .
+ TYPES:
+ BEGIN OF t_sheet,
+ name TYPE string,
+ sheetid TYPE string,
+ id TYPE string,
+ END OF t_sheet .
+ TYPES:
+ BEGIN OF t_workbookpr,
+ codename TYPE string,
+ defaultthemeversion TYPE string,
+ END OF t_workbookpr .
+ TYPES:
+ BEGIN OF t_sheetpr,
+ codename TYPE string,
+ END OF t_sheetpr .
+
+ DATA w_row_int TYPE yecb_cell_row VALUE 1. "#EC NOTEXT . . . . . . . . . . " .
+ DATA w_col_int TYPE yecb_cell_column VALUE 1. "#EC NOTEXT . . . . . . . . . . " .
+*"* private components of class ZCL_EXCEL_CONVERTER
+*"* do not include other source files here!!!
+ PRIVATE SECTION.
+ CLASS-METHODS get_subclasses
+ IMPORTING
+ is_clskey TYPE seoclskey
+ CHANGING
+ ct_classes TYPE seor_implementing_keys.
+
+ DATA wo_excel TYPE REF TO ycl_ecb .
+ DATA wo_worksheet TYPE REF TO ycl_ecb_worksheet .
+ DATA wo_autofilter TYPE REF TO ycl_ecb_autofilter .
+ DATA wo_table TYPE REF TO data .
+ DATA wo_data TYPE REF TO data .
+ DATA wt_fieldcatalog TYPE yecb_t_converter_fcat .
+ DATA ws_layout TYPE yecb_s_converter_layo .
+ DATA wt_colors TYPE yecb_t_converter_col .
+ DATA wt_filter TYPE yecb_t_converter_fil .
+ CLASS-DATA wt_objects TYPE tt_alv_types .
+ CLASS-DATA w_fcount TYPE n LENGTH 3 .
+ DATA wt_sort_values TYPE tt_sort_values .
+ DATA wt_subtotal_rows TYPE tt_subtotal_rows .
+ DATA wt_styles TYPE tt_styles .
+ CONSTANTS c_type_hdr TYPE c VALUE 'H'. "#EC NOTEXT
+ CONSTANTS c_type_str TYPE c VALUE 'P'. "#EC NOTEXT
+ CONSTANTS c_type_nor TYPE c VALUE 'N'. "#EC NOTEXT
+ CONSTANTS c_type_sub TYPE c VALUE 'S'. "#EC NOTEXT
+ CONSTANTS c_type_tot TYPE c VALUE 'T'. "#EC NOTEXT
+ DATA wt_color_styles TYPE tt_color_styles .
+ CLASS-DATA ws_option TYPE yecb_s_converter_option .
+ CLASS-DATA ws_indx TYPE indx .
+
+ CLASS-METHODS init_option .
+ CLASS-METHODS get_alv_converters.
+ METHODS bind_table
+ IMPORTING
+ !i_style_table TYPE yecb_table_style
+ RETURNING
+ VALUE(r_freeze_col) TYPE int1
+ RAISING
+ ycx_ecb .
+ METHODS bind_cells
+ RETURNING
+ VALUE(r_freeze_col) TYPE int1
+ RAISING
+ ycx_ecb .
+ METHODS clean_fieldcatalog .
+ METHODS create_color_style
+ IMPORTING
+ !i_style TYPE yecb_cell_style
+ !is_colors TYPE yecb_s_converter_col
+ RETURNING
+ VALUE(ro_style) TYPE REF TO ycl_ecb_style .
+ METHODS create_formular_subtotal
+ IMPORTING
+ !i_row_int_start TYPE yecb_cell_row
+ !i_row_int_end TYPE yecb_cell_row
+ !i_column TYPE yecb_cell_column_alpha
+ !i_totals_function TYPE yecb_table_totals_function
+ RETURNING
+ VALUE(r_formula) TYPE string .
+ METHODS create_formular_total
+ IMPORTING
+ !i_row_int TYPE yecb_cell_row
+ !i_column TYPE yecb_cell_column_alpha
+ !i_totals_function TYPE yecb_table_totals_function
+ RETURNING
+ VALUE(r_formula) TYPE string .
+ METHODS create_style_hdr
+ IMPORTING
+ !i_alignment TYPE yecb_alignment OPTIONAL
+ RETURNING
+ VALUE(ro_style) TYPE REF TO ycl_ecb_style .
+ METHODS create_style_normal
+ IMPORTING
+ !i_alignment TYPE yecb_alignment OPTIONAL
+ !i_inttype TYPE abap_typekind OPTIONAL
+ !i_decimals TYPE int1 OPTIONAL
+ RETURNING
+ VALUE(ro_style) TYPE REF TO ycl_ecb_style .
+ METHODS create_style_stripped
+ IMPORTING
+ !i_alignment TYPE yecb_alignment OPTIONAL
+ !i_inttype TYPE abap_typekind OPTIONAL
+ !i_decimals TYPE int1 OPTIONAL
+ RETURNING
+ VALUE(ro_style) TYPE REF TO ycl_ecb_style .
+ METHODS create_style_subtotal
+ IMPORTING
+ !i_alignment TYPE yecb_alignment OPTIONAL
+ !i_inttype TYPE abap_typekind OPTIONAL
+ !i_decimals TYPE int1 OPTIONAL
+ RETURNING
+ VALUE(ro_style) TYPE REF TO ycl_ecb_style .
+ METHODS create_style_total
+ IMPORTING
+ !i_alignment TYPE yecb_alignment OPTIONAL
+ !i_inttype TYPE abap_typekind OPTIONAL
+ !i_decimals TYPE int1 OPTIONAL
+ RETURNING
+ VALUE(ro_style) TYPE REF TO ycl_ecb_style .
+ METHODS create_table .
+ METHODS create_text_subtotal
+ IMPORTING
+ !i_value TYPE any
+ !i_totals_function TYPE yecb_table_totals_function
+ RETURNING
+ VALUE(r_text) TYPE string .
+ METHODS create_worksheet
+ IMPORTING
+ !i_table TYPE flag DEFAULT 'X'
+ !i_style_table TYPE yecb_table_style
+ RAISING
+ ycx_ecb .
+ METHODS execute_converter
+ IMPORTING
+ !io_object TYPE REF TO object
+ !it_table TYPE STANDARD TABLE
+ RAISING
+ ycx_ecb .
+ METHODS get_color_style
+ IMPORTING
+ !i_row TYPE yecb_cell_row
+ !i_fieldname TYPE fieldname
+ !i_style TYPE yecb_cell_style
+ RETURNING
+ VALUE(r_style) TYPE yecb_cell_style .
+ METHODS get_function_number
+ IMPORTING
+ !i_totals_function TYPE yecb_table_totals_function
+ RETURNING
+ VALUE(r_function_number) TYPE int1 .
+ METHODS get_style
+ IMPORTING
+ !i_type TYPE ty_style_type
+ !i_alignment TYPE yecb_alignment DEFAULT space
+ !i_inttype TYPE abap_typekind DEFAULT space
+ !i_decimals TYPE int1 DEFAULT 0
+ RETURNING
+ VALUE(r_style) TYPE yecb_cell_style .
+ METHODS loop_normal
+ IMPORTING
+ !i_row_int TYPE yecb_cell_row
+ !i_col_int TYPE yecb_cell_column
+ RETURNING
+ VALUE(r_freeze_col) TYPE int1
+ RAISING
+ ycx_ecb .
+ METHODS loop_subtotal
+ IMPORTING
+ !i_row_int TYPE yecb_cell_row
+ !i_col_int TYPE yecb_cell_column
+ RETURNING
+ VALUE(r_freeze_col) TYPE int1
+ RAISING
+ ycx_ecb .
+ METHODS set_autofilter_area .
+ METHODS set_cell_format
+ IMPORTING
+ !i_inttype TYPE abap_typekind
+ !i_decimals TYPE int1
+ RETURNING
+ VALUE(r_format) TYPE yecb_number_format .
+ METHODS set_fieldcatalog .
+ENDCLASS.
+
+
+
+CLASS ycl_ecb_converter IMPLEMENTATION.
+
+
+ METHOD ask_option.
+ DATA: ls_sval TYPE sval,
+ lt_sval TYPE STANDARD TABLE OF sval,
+ l_returncode TYPE string,
+ lt_fields TYPE ddfields,
+ ls_fields TYPE dfies.
+
+ FIELD-SYMBOLS: TYPE any.
+
+ rs_option = ws_option.
+
+ CALL FUNCTION 'DDIF_FIELDINFO_GET'
+ EXPORTING
+ tabname = 'ZEXCEL_S_CONVERTER_OPTION'
+ TABLES
+ dfies_tab = lt_fields
+ EXCEPTIONS
+ not_found = 1
+ internal_error = 2
+ OTHERS = 3.
+ IF sy-subrc <> 0.
+ MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
+ WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
+ ENDIF.
+
+ LOOP AT lt_fields INTO ls_fields.
+ ASSIGN COMPONENT ls_fields-fieldname OF STRUCTURE ws_option TO .
+ IF sy-subrc = 0.
+ CLEAR ls_sval.
+ ls_sval-tabname = ls_fields-tabname.
+ ls_sval-fieldname = ls_fields-fieldname.
+ ls_sval-value = .
+ ls_sval-field_attr = space.
+ ls_sval-field_obl = space.
+ ls_sval-comp_code = space.
+ ls_sval-fieldtext = ls_fields-scrtext_m.
+ ls_sval-comp_tab = space.
+ ls_sval-comp_field = space.
+ ls_sval-novaluehlp = space.
+ INSERT ls_sval INTO TABLE lt_sval.
+ ENDIF.
+ ENDLOOP.
+
+ CALL FUNCTION 'POPUP_GET_VALUES'
+ EXPORTING
+ popup_title = 'Excel creation options'(008)
+ IMPORTING
+ returncode = l_returncode
+ TABLES
+ fields = lt_sval
+ EXCEPTIONS
+ error_in_fields = 1
+ OTHERS = 2.
+ IF sy-subrc <> 0.
+ MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
+ WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
+ ELSEIF l_returncode = 'A'.
+ RAISE EXCEPTION TYPE ycx_ecb.
+ ELSE.
+ LOOP AT lt_sval INTO ls_sval.
+ ASSIGN COMPONENT ls_sval-fieldname OF STRUCTURE ws_option TO .
+ IF sy-subrc = 0.
+ = ls_sval-value.
+ ENDIF.
+ ENDLOOP.
+ set_option( is_option = ws_option ) .
+ rs_option = ws_option.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD bind_cells.
+
+* Do we need subtotals with grouping
+ READ TABLE wt_fieldcatalog TRANSPORTING NO FIELDS WITH KEY is_subtotalled = abap_true.
+ IF sy-subrc = 0 .
+ r_freeze_col = loop_subtotal( i_row_int = w_row_int
+ i_col_int = w_col_int ) .
+ ELSE.
+ r_freeze_col = loop_normal( i_row_int = w_row_int
+ i_col_int = w_col_int ) .
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD bind_table.
+ DATA: lt_field_catalog TYPE yecb_t_fieldcatalog,
+ ls_field_catalog TYPE yecb_s_fieldcatalog,
+ ls_fcat TYPE yecb_s_converter_fcat,
+ lo_column TYPE REF TO ycl_ecb_column,
+ lv_col_int TYPE yecb_cell_column,
+ lv_col_alpha TYPE yecb_cell_column_alpha,
+ ls_settings TYPE yecb_s_table_settings,
+ lv_line TYPE i.
+
+ FIELD-SYMBOLS: TYPE ANY TABLE.
+
+ ASSIGN wo_data->* TO .
+
+ ls_settings-table_style = i_style_table.
+ ls_settings-top_left_column = ycl_ecb_common=>convert_column2alpha( ip_column = w_col_int ).
+ ls_settings-top_left_row = w_row_int.
+ ls_settings-show_row_stripes = ws_layout-is_stripped.
+
+ DESCRIBE TABLE wt_fieldcatalog LINES lv_line.
+ lv_line = lv_line + 1 + w_col_int.
+ ls_settings-bottom_right_column = ycl_ecb_common=>convert_column2alpha( ip_column = lv_line ).
+
+ DESCRIBE TABLE LINES lv_line.
+ ls_settings-bottom_right_row = lv_line + 1 + w_row_int.
+ SORT wt_fieldcatalog BY position.
+ LOOP AT wt_fieldcatalog INTO ls_fcat.
+ MOVE-CORRESPONDING ls_fcat TO ls_field_catalog.
+ ls_field_catalog-dynpfld = abap_true.
+ INSERT ls_field_catalog INTO TABLE lt_field_catalog.
+ ENDLOOP.
+
+ wo_worksheet->bind_table(
+ EXPORTING
+ ip_table =
+ it_field_catalog = lt_field_catalog
+ is_table_settings = ls_settings
+ IMPORTING
+ es_table_settings = ls_settings
+ ).
+ LOOP AT wt_fieldcatalog INTO ls_fcat.
+ lv_col_int = w_col_int + ls_fcat-position - 1.
+ lv_col_alpha = ycl_ecb_common=>convert_column2alpha( lv_col_int ).
+* Freeze panes
+ IF ls_fcat-fix_column = abap_true.
+ ADD 1 TO r_freeze_col.
+ ENDIF.
+* Now let's check for optimized
+ IF ls_fcat-is_optimized = abap_true.
+ lo_column = wo_worksheet->get_column( ip_column = lv_col_alpha ).
+ lo_column->set_auto_size( ip_auto_size = abap_true ) .
+ ENDIF.
+* Now let's check for visible
+ IF ls_fcat-is_hidden = abap_true.
+ lo_column = wo_worksheet->get_column( ip_column = lv_col_alpha ).
+ lo_column->set_visible( ip_visible = abap_false ) .
+ ENDIF.
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+ METHOD class_constructor.
+ DATA: ls_objects TYPE ts_alv_types.
+ DATA: ls_option TYPE yecb_s_converter_option,
+ l_uname TYPE sy-uname.
+
+ GET PARAMETER ID 'ZUS' FIELD l_uname.
+ IF l_uname IS INITIAL OR l_uname = space.
+ l_uname = sy-uname.
+ ENDIF.
+
+ get_alv_converters( ).
+
+ CONCATENATE 'EXCEL_' sy-uname INTO ws_indx-srtfd.
+
+ IMPORT p1 = ls_option FROM DATABASE indx(xl) TO ws_indx ID ws_indx-srtfd.
+
+ IF sy-subrc = 0.
+ ws_option = ls_option.
+ ELSE.
+ init_option( ) .
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD clean_fieldcatalog.
+ DATA: l_position TYPE tabfdpos.
+
+ FIELD-SYMBOLS: TYPE yecb_s_converter_fcat.
+
+ SORT wt_fieldcatalog BY position col_id.
+
+ CLEAR l_position.
+ LOOP AT wt_fieldcatalog ASSIGNING .
+ ADD 1 TO l_position.
+ -position = l_position.
+* Default stype with alignment and format
+ -style_hdr = get_style( i_type = c_type_hdr
+ i_alignment = -alignment ).
+ IF ws_layout-is_stripped = abap_true.
+ -style_stripped = get_style( i_type = c_type_str
+ i_alignment = -alignment
+ i_inttype = -inttype
+ i_decimals = -decimals ).
+ ENDIF.
+ -style_normal = get_style( i_type = c_type_nor
+ i_alignment = -alignment
+ i_inttype = -inttype
+ i_decimals = -decimals ).
+ -style_subtotal = get_style( i_type = c_type_sub
+ i_alignment = -alignment
+ i_inttype = -inttype
+ i_decimals = -decimals ).
+ -style_total = get_style( i_type = c_type_tot
+ i_alignment = -alignment
+ i_inttype = -inttype
+ i_decimals = -decimals ).
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+ METHOD convert.
+
+ IF is_option IS SUPPLIED.
+ ws_option = is_option.
+ ENDIF.
+
+ execute_converter( EXPORTING io_object = io_alv
+ it_table = it_table ) .
+
+ IF io_worksheet IS SUPPLIED AND io_worksheet IS BOUND.
+ wo_worksheet = io_worksheet.
+ ENDIF.
+ IF co_excel IS SUPPLIED.
+ IF co_excel IS NOT BOUND.
+ CREATE OBJECT co_excel.
+ co_excel->yif_ecb_book_properties~creator = sy-uname.
+ ENDIF.
+ wo_excel = co_excel.
+ ENDIF.
+
+* Move table to data object and clean it up
+ IF wt_fieldcatalog IS NOT INITIAL.
+ create_table( ).
+ ELSE.
+ wo_data = wo_table .
+ ENDIF.
+
+ IF wo_excel IS NOT BOUND.
+ CREATE OBJECT wo_excel.
+ wo_excel->yif_ecb_book_properties~creator = sy-uname.
+ ENDIF.
+ IF wo_worksheet IS NOT BOUND.
+ " Get active sheet
+ wo_worksheet = wo_excel->get_active_worksheet( ).
+ wo_worksheet->set_title( ip_title = 'Sheet1'(001) ).
+ ENDIF.
+
+ IF i_row_int <= 0.
+ w_row_int = 1.
+ ELSE.
+ w_row_int = i_row_int.
+ ENDIF.
+ IF i_column_int <= 0.
+ w_col_int = 1.
+ ELSE.
+ w_col_int = i_column_int.
+ ENDIF.
+
+ create_worksheet( i_table = i_table
+ i_style_table = i_style_table ) .
+
+ ENDMETHOD.
+
+
+ METHOD create_color_style.
+ DATA: ls_styles TYPE ts_styles.
+ DATA: lo_style TYPE REF TO ycl_ecb_style.
+
+ READ TABLE wt_styles INTO ls_styles WITH KEY guid = i_style.
+ IF sy-subrc = 0.
+ lo_style = wo_excel->add_new_style( ).
+ lo_style->font->bold = ls_styles-style->font->bold.
+ lo_style->alignment->horizontal = ls_styles-style->alignment->horizontal.
+ lo_style->number_format->format_code = ls_styles-style->number_format->format_code.
+
+ lo_style->font->color-rgb = is_colors-fontcolor.
+ lo_style->fill->filltype = ycl_ecb_style_fill=>c_fill_solid.
+ lo_style->fill->fgcolor-rgb = is_colors-fillcolor.
+
+ ro_style = lo_style.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD create_formular_subtotal.
+ DATA: l_row_alpha_start TYPE string,
+ l_row_alpha_end TYPE string,
+ l_func_num TYPE string.
+
+ l_row_alpha_start = i_row_int_start.
+ l_row_alpha_end = i_row_int_end.
+
+ l_func_num = get_function_number( i_totals_function = i_totals_function ).
+ CONCATENATE 'SUBTOTAL(' l_func_num ',' i_column l_row_alpha_start ':' i_column l_row_alpha_end ')' INTO r_formula.
+ ENDMETHOD.
+
+
+ METHOD create_formular_total.
+ DATA: l_row_alpha TYPE string,
+ l_row_e_alpha TYPE string.
+
+ l_row_alpha = w_row_int + 1.
+ l_row_e_alpha = i_row_int.
+
+ CONCATENATE i_totals_function '(' i_column l_row_alpha ':' i_column l_row_e_alpha ')' INTO r_formula.
+ ENDMETHOD.
+
+
+ METHOD create_path.
+ DATA: l_sep TYPE c,
+ l_path TYPE string,
+ l_return TYPE i.
+
+ CLEAR r_path.
+
+ " Save the file
+ cl_gui_frontend_services=>get_sapgui_workdir(
+ CHANGING
+ sapworkdir = l_path
+ EXCEPTIONS
+ get_sapworkdir_failed = 1
+ cntl_error = 2
+ error_no_gui = 3
+ not_supported_by_gui = 4
+ ).
+ IF sy-subrc <> 0.
+ CONCATENATE 'Excel_' w_fcount '.xlsx' INTO r_path.
+ ELSE.
+ DO.
+ ADD 1 TO w_fcount.
+*-obtain file separator character---------------------------------------
+ CALL METHOD cl_gui_frontend_services=>get_file_separator
+ CHANGING
+ file_separator = l_sep
+ EXCEPTIONS
+ cntl_error = 1
+ error_no_gui = 2
+ not_supported_by_gui = 3
+ OTHERS = 4.
+
+ IF sy-subrc <> 0.
+ l_sep = ''.
+ ENDIF.
+
+ CONCATENATE l_path l_sep 'Excel_' w_fcount '.xlsx' INTO r_path.
+
+ IF cl_gui_frontend_services=>file_exist( file = r_path ) = abap_true.
+ cl_gui_frontend_services=>file_delete( EXPORTING filename = r_path
+ CHANGING rc = l_return
+ EXCEPTIONS OTHERS = 1 ).
+ IF sy-subrc = 0 .
+ RETURN.
+ ENDIF.
+ ELSE.
+ RETURN.
+ ENDIF.
+ ENDDO.
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD create_style_hdr.
+ DATA: lo_style TYPE REF TO ycl_ecb_style.
+
+ lo_style = wo_excel->add_new_style( ).
+ lo_style->font->bold = abap_true.
+ lo_style->font->color-rgb = ycl_ecb_style_color=>c_white.
+ lo_style->fill->filltype = ycl_ecb_style_fill=>c_fill_solid.
+ lo_style->fill->fgcolor-rgb = 'FF4F81BD'.
+ IF i_alignment IS SUPPLIED AND i_alignment IS NOT INITIAL.
+ lo_style->alignment->horizontal = i_alignment.
+ ENDIF.
+ ro_style = lo_style .
+ ENDMETHOD.
+
+
+ METHOD create_style_normal.
+ DATA: lo_style TYPE REF TO ycl_ecb_style,
+ l_format TYPE yecb_number_format.
+
+ IF i_inttype IS SUPPLIED AND i_inttype IS NOT INITIAL.
+ l_format = set_cell_format( i_inttype = i_inttype
+ i_decimals = i_decimals ) .
+ ENDIF.
+ IF l_format IS NOT INITIAL OR
+ ( i_alignment IS SUPPLIED AND i_alignment IS NOT INITIAL ) .
+
+ lo_style = wo_excel->add_new_style( ).
+
+ IF i_alignment IS SUPPLIED AND i_alignment IS NOT INITIAL.
+ lo_style->alignment->horizontal = i_alignment.
+ ENDIF.
+
+ IF l_format IS NOT INITIAL.
+ lo_style->number_format->format_code = l_format.
+ ENDIF.
+
+ ro_style = lo_style .
+
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD create_style_stripped.
+ DATA: lo_style TYPE REF TO ycl_ecb_style.
+ DATA: l_format TYPE yecb_number_format.
+
+ lo_style = wo_excel->add_new_style( ).
+ lo_style->fill->filltype = ycl_ecb_style_fill=>c_fill_solid.
+ lo_style->fill->fgcolor-rgb = 'FFDBE5F1'.
+ IF i_alignment IS SUPPLIED AND i_alignment IS NOT INITIAL.
+ lo_style->alignment->horizontal = i_alignment.
+ ENDIF.
+ IF i_inttype IS SUPPLIED AND i_inttype IS NOT INITIAL.
+ l_format = set_cell_format( i_inttype = i_inttype
+ i_decimals = i_decimals ) .
+ IF l_format IS NOT INITIAL.
+ lo_style->number_format->format_code = l_format.
+ ENDIF.
+ ENDIF.
+ ro_style = lo_style.
+
+ ENDMETHOD.
+
+
+ METHOD create_style_subtotal.
+ DATA: lo_style TYPE REF TO ycl_ecb_style.
+ DATA: l_format TYPE yecb_number_format.
+
+ lo_style = wo_excel->add_new_style( ).
+ lo_style->font->bold = abap_true.
+
+ IF i_alignment IS SUPPLIED AND i_alignment IS NOT INITIAL.
+ lo_style->alignment->horizontal = i_alignment.
+ ENDIF.
+ IF i_inttype IS SUPPLIED AND i_inttype IS NOT INITIAL.
+ l_format = set_cell_format( i_inttype = i_inttype
+ i_decimals = i_decimals ) .
+ IF l_format IS NOT INITIAL.
+ lo_style->number_format->format_code = l_format.
+ ENDIF.
+ ENDIF.
+
+ ro_style = lo_style .
+
+ ENDMETHOD.
+
+
+ METHOD create_style_total.
+ DATA: lo_style TYPE REF TO ycl_ecb_style.
+ DATA: l_format TYPE yecb_number_format.
+
+ lo_style = wo_excel->add_new_style( ).
+ lo_style->font->bold = abap_true.
+
+ CREATE OBJECT lo_style->borders->top.
+ lo_style->borders->top->border_style = ycl_ecb_style_border=>c_border_thin.
+ lo_style->borders->top->border_color-rgb = ycl_ecb_style_color=>c_black.
+
+ CREATE OBJECT lo_style->borders->right.
+ lo_style->borders->right->border_style = ycl_ecb_style_border=>c_border_none.
+ lo_style->borders->right->border_color-rgb = ycl_ecb_style_color=>c_black.
+
+ CREATE OBJECT lo_style->borders->down.
+ lo_style->borders->down->border_style = ycl_ecb_style_border=>c_border_double.
+ lo_style->borders->down->border_color-rgb = ycl_ecb_style_color=>c_black.
+
+ CREATE OBJECT lo_style->borders->left.
+ lo_style->borders->left->border_style = ycl_ecb_style_border=>c_border_none.
+ lo_style->borders->left->border_color-rgb = ycl_ecb_style_color=>c_black.
+
+ IF i_alignment IS SUPPLIED AND i_alignment IS NOT INITIAL.
+ lo_style->alignment->horizontal = i_alignment.
+ ENDIF.
+ IF i_inttype IS SUPPLIED AND i_inttype IS NOT INITIAL.
+ l_format = set_cell_format( i_inttype = i_inttype
+ i_decimals = i_decimals ) .
+ IF l_format IS NOT INITIAL.
+ lo_style->number_format->format_code = l_format.
+ ENDIF.
+ ENDIF.
+
+ ro_style = lo_style .
+
+ ENDMETHOD.
+
+
+ METHOD create_table.
+ TYPES: BEGIN OF ts_output,
+ fieldname TYPE fieldname,
+ function TYPE funcname,
+ END OF ts_output.
+
+ DATA: lo_data TYPE REF TO data.
+ DATA: lo_addit TYPE REF TO cl_abap_elemdescr,
+ lt_components_tab TYPE cl_abap_structdescr=>component_table,
+ ls_components TYPE abap_componentdescr,
+ lo_table TYPE REF TO cl_abap_tabledescr,
+ lo_struc TYPE REF TO cl_abap_structdescr.
+
+ FIELD-SYMBOLS: TYPE yecb_s_converter_fcat,
+ TYPE any,
+ TYPE STANDARD TABLE,
+ TYPE any,
+ TYPE STANDARD TABLE.
+
+ SORT wt_fieldcatalog BY position.
+ ASSIGN wo_table->* TO .
+
+ READ TABLE ASSIGNING INDEX 1.
+ IF sy-subrc EQ 0 .
+ LOOP AT wt_fieldcatalog ASSIGNING .
+ ASSIGN COMPONENT -columnname OF STRUCTURE TO .
+ IF sy-subrc = 0.
+ ls_components-name = -columnname.
+ TRY.
+ lo_addit ?= cl_abap_typedescr=>describe_by_data( ).
+ CATCH cx_sy_move_cast_error.
+ CLEAR lo_addit.
+ DELETE TABLE wt_fieldcatalog FROM .
+ ENDTRY.
+ IF lo_addit IS BOUND.
+ ls_components-type = lo_addit .
+ INSERT ls_components INTO TABLE lt_components_tab.
+ ENDIF.
+ ENDIF.
+ ENDLOOP.
+ IF lt_components_tab IS NOT INITIAL.
+ "create new line type
+ TRY.
+ lo_struc = cl_abap_structdescr=>create( p_components = lt_components_tab
+ p_strict = abap_false ).
+ CATCH cx_sy_struct_creation.
+ RETURN. " We can not do anything in this case.
+ ENDTRY.
+
+ lo_table = cl_abap_tabledescr=>create( lo_struc ).
+
+ CREATE DATA wo_data TYPE HANDLE lo_table.
+ CREATE DATA lo_data TYPE HANDLE lo_struc.
+
+ ASSIGN wo_data->* TO .
+ ASSIGN lo_data->* TO .
+ LOOP AT ASSIGNING .
+ CLEAR .
+ MOVE-CORRESPONDING TO .
+ APPEND TO .
+ ENDLOOP.
+ ENDIF.
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD create_text_subtotal.
+ DATA: l_string(256) TYPE c,
+ l_func TYPE string.
+
+ CASE i_totals_function.
+ WHEN ycl_ecb_table=>totals_function_sum. " Total
+ l_func = 'Total'(003).
+ WHEN ycl_ecb_table=>totals_function_min. " Minimum
+ l_func = 'Minimum'(004).
+ WHEN ycl_ecb_table=>totals_function_max. " Maximum
+ l_func = 'Maximum'(005).
+ WHEN ycl_ecb_table=>totals_function_average. " Mean Value
+ l_func = 'Average'(006).
+ WHEN ycl_ecb_table=>totals_function_count. " Count
+ l_func = 'Count'(007).
+ WHEN OTHERS.
+ CLEAR l_func.
+ ENDCASE.
+
+ l_string = i_value.
+
+ CONCATENATE l_string l_func INTO r_text SEPARATED BY space.
+
+ ENDMETHOD.
+
+
+ METHOD create_worksheet.
+ DATA: l_freeze_col TYPE i.
+
+ IF wo_data IS BOUND AND wo_worksheet IS BOUND.
+
+ wo_worksheet->yif_ecb_sheet_properties~summarybelow = yif_ecb_sheet_properties=>c_below_on. " By default is on
+
+ IF wt_fieldcatalog IS INITIAL.
+ set_fieldcatalog( ) .
+ ELSE.
+ clean_fieldcatalog( ) .
+ ENDIF.
+
+ IF i_table = abap_true.
+ l_freeze_col = bind_table( i_style_table = i_style_table ) .
+ ELSEIF wt_filter IS NOT INITIAL.
+* Let's check for filter.
+ wo_autofilter = wo_excel->add_new_autofilter( io_sheet = wo_worksheet ).
+ l_freeze_col = bind_cells( ) .
+ set_autofilter_area( ) .
+ ELSE.
+ l_freeze_col = bind_cells( ) .
+ ENDIF.
+
+* Check for freeze panes
+ IF ws_layout-is_fixed = abap_true.
+ IF l_freeze_col = 0.
+ l_freeze_col = w_col_int.
+ ENDIF.
+ wo_worksheet->freeze_panes( EXPORTING ip_num_columns = l_freeze_col
+ ip_num_rows = w_row_int ) .
+ ENDIF.
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD execute_converter.
+ DATA: lo_if TYPE REF TO yif_ecb_converter,
+ ls_types TYPE ts_alv_types,
+ lo_addit TYPE REF TO cl_abap_classdescr,
+ lo_addit_superclass TYPE REF TO cl_abap_classdescr.
+
+ IF io_object IS BOUND.
+ TRY.
+ lo_addit ?= cl_abap_typedescr=>describe_by_object_ref( io_object ).
+ CATCH cx_sy_move_cast_error.
+ RAISE EXCEPTION TYPE ycx_ecb.
+ ENDTRY.
+ ls_types-seoclass = lo_addit->get_relative_name( ).
+ READ TABLE wt_objects INTO ls_types WITH TABLE KEY seoclass = ls_types-seoclass.
+ IF sy-subrc NE 0.
+ DO.
+ FREE lo_addit_superclass.
+ lo_addit_superclass = lo_addit->get_super_class_type( ).
+ IF lo_addit_superclass IS INITIAL.
+ CLEAR ls_types-clsname.
+ EXIT.
+ ENDIF.
+ lo_addit = lo_addit_superclass.
+ ls_types-seoclass = lo_addit->get_relative_name( ).
+ READ TABLE wt_objects INTO ls_types WITH TABLE KEY seoclass = ls_types-seoclass.
+ IF sy-subrc EQ 0.
+ EXIT.
+ ENDIF.
+ ENDDO.
+ ENDIF.
+ IF ls_types-clsname IS NOT INITIAL.
+ CREATE OBJECT lo_if TYPE (ls_types-clsname).
+ lo_if->create_fieldcatalog(
+ EXPORTING
+ is_option = ws_option
+ io_object = io_object
+ it_table = it_table
+ IMPORTING
+ es_layout = ws_layout
+ et_fieldcatalog = wt_fieldcatalog
+ eo_table = wo_table
+ et_colors = wt_colors
+ et_filter = wt_filter
+ ).
+* data lines of highest level.
+ IF ws_layout-max_subtotal_level > 0. ADD 1 TO ws_layout-max_subtotal_level. ENDIF.
+ ELSE.
+ RAISE EXCEPTION TYPE ycx_ecb.
+ ENDIF.
+ ELSE.
+ CLEAR wt_fieldcatalog.
+ GET REFERENCE OF it_table INTO wo_table.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD get_alv_converters.
+ DATA:
+ lt_direct_implementations TYPE seor_implementing_keys,
+ lt_all_implementations TYPE seor_implementing_keys,
+ ls_impkey TYPE seor_implementing_key,
+ ls_classkey TYPE seoclskey,
+ lr_implementation TYPE REF TO yif_ecb_converter,
+ ls_object TYPE ts_alv_types,
+ lr_classdescr TYPE REF TO cl_abap_classdescr.
+
+ ls_classkey-clsname = 'ZIF_EXCEL_CONVERTER'.
+
+ CALL FUNCTION 'SEO_INTERFACE_IMPLEM_GET_ALL'
+ EXPORTING
+ intkey = ls_classkey
+ IMPORTING
+ impkeys = lt_direct_implementations
+ EXCEPTIONS
+ OTHERS = 2.
+
+ CHECK sy-subrc = 0.
+
+ LOOP AT lt_direct_implementations INTO ls_impkey.
+ lr_classdescr ?= cl_abap_classdescr=>describe_by_name( ls_impkey-clsname ).
+ IF lr_classdescr->is_instantiatable( ) = abap_true.
+ APPEND ls_impkey TO lt_all_implementations.
+ ENDIF.
+
+ ls_classkey-clsname = ls_impkey-clsname.
+ get_subclasses( EXPORTING is_clskey = ls_classkey CHANGING ct_classes = lt_all_implementations ).
+ ENDLOOP.
+
+ SORT lt_all_implementations BY clsname.
+ DELETE ADJACENT DUPLICATES FROM lt_all_implementations COMPARING clsname.
+
+ LOOP AT lt_all_implementations INTO ls_impkey.
+ CLEAR ls_object.
+ CREATE OBJECT lr_implementation TYPE (ls_impkey-clsname).
+ ls_object-seoclass = lr_implementation->get_supported_class( ).
+
+ IF ls_object-seoclass IS NOT INITIAL.
+ ls_object-clsname = ls_impkey-clsname.
+ INSERT ls_object INTO TABLE wt_objects.
+ ENDIF.
+ ENDLOOP.
+ ENDMETHOD.
+
+
+ METHOD get_color_style.
+ DATA: ls_colors TYPE yecb_s_converter_col,
+ ls_color_styles TYPE ts_color_styles,
+ lo_style TYPE REF TO ycl_ecb_style.
+
+ r_style = i_style. " Default we change nothing
+
+ IF wt_colors IS NOT INITIAL.
+* Full line has color
+ READ TABLE wt_colors INTO ls_colors WITH KEY rownumber = i_row
+ columnname = space.
+ IF sy-subrc = 0.
+ READ TABLE wt_color_styles INTO ls_color_styles WITH KEY guid_old = i_style
+ fontcolor = ls_colors-fontcolor
+ fillcolor = ls_colors-fillcolor.
+ IF sy-subrc = 0.
+ r_style = ls_color_styles-style_new->get_guid( ).
+ ELSE.
+ lo_style = create_color_style( i_style = i_style
+ is_colors = ls_colors ) .
+ r_style = lo_style->get_guid( ) .
+ ls_color_styles-guid_old = i_style.
+ ls_color_styles-fontcolor = ls_colors-fontcolor.
+ ls_color_styles-fillcolor = ls_colors-fillcolor.
+ ls_color_styles-style_new = lo_style.
+ INSERT ls_color_styles INTO TABLE wt_color_styles.
+ ENDIF.
+ ELSE.
+* Only field has color
+ READ TABLE wt_colors INTO ls_colors WITH KEY rownumber = i_row
+ columnname = i_fieldname.
+ IF sy-subrc = 0.
+ READ TABLE wt_color_styles INTO ls_color_styles WITH KEY guid_old = i_style
+ fontcolor = ls_colors-fontcolor
+ fillcolor = ls_colors-fillcolor.
+ IF sy-subrc = 0.
+ r_style = ls_color_styles-style_new->get_guid( ).
+ ELSE.
+ lo_style = create_color_style( i_style = i_style
+ is_colors = ls_colors ) .
+ ls_color_styles-guid_old = i_style.
+ ls_color_styles-fontcolor = ls_colors-fontcolor.
+ ls_color_styles-fillcolor = ls_colors-fillcolor.
+ ls_color_styles-style_new = lo_style.
+ INSERT ls_color_styles INTO TABLE wt_color_styles.
+ r_style = ls_color_styles-style_new->get_guid( ).
+ ENDIF.
+ ELSE.
+ r_style = i_style.
+ ENDIF.
+ ENDIF.
+ ELSE.
+ r_style = i_style.
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD get_file.
+ DATA: lo_excel_writer TYPE REF TO yif_ecb_writer.
+
+ DATA: ls_seoclass TYPE seoclass.
+
+
+ IF wo_excel IS BOUND.
+ CREATE OBJECT lo_excel_writer TYPE ycl_ecb_writer_2007.
+ e_file = lo_excel_writer->write_file( wo_excel ).
+
+ SELECT SINGLE * INTO ls_seoclass
+ FROM seoclass
+ WHERE clsname = 'CL_BCS_CONVERT'.
+
+ IF sy-subrc = 0.
+ CALL METHOD (ls_seoclass-clsname)=>xstring_to_solix
+ EXPORTING
+ iv_xstring = e_file
+ RECEIVING
+ et_solix = et_file.
+ e_bytecount = xstrlen( e_file ).
+ ELSE.
+ " Convert to binary
+ CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
+ EXPORTING
+ buffer = e_file
+ IMPORTING
+ output_length = e_bytecount
+ TABLES
+ binary_tab = et_file.
+ ENDIF.
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD get_function_number.
+*Number Function
+*1 AVERAGE
+*2 COUNT
+*3 COUNTA
+*4 MAX
+*5 MIN
+*6 PRODUCT
+*7 STDEV
+*8 STDEVP
+*9 SUM
+*10 VAR
+*11 VARP
+
+ CASE i_totals_function.
+ WHEN ycl_ecb_table=>totals_function_sum. " Total
+ r_function_number = 9.
+ WHEN ycl_ecb_table=>totals_function_min. " Minimum
+ r_function_number = 5.
+ WHEN ycl_ecb_table=>totals_function_max. " Maximum
+ r_function_number = 4.
+ WHEN ycl_ecb_table=>totals_function_average. " Mean Value
+ r_function_number = 1.
+ WHEN ycl_ecb_table=>totals_function_count. " Count
+ r_function_number = 2.
+ WHEN OTHERS.
+ CLEAR r_function_number.
+ ENDCASE.
+ ENDMETHOD.
+
+
+ METHOD get_option.
+
+ rs_option = ws_option.
+
+ ENDMETHOD.
+
+
+ METHOD get_style.
+ DATA: ls_styles TYPE ts_styles,
+ lo_style TYPE REF TO ycl_ecb_style.
+
+ CLEAR r_style.
+
+ READ TABLE wt_styles INTO ls_styles WITH TABLE KEY type = i_type
+ alignment = i_alignment
+ inttype = i_inttype
+ decimals = i_decimals.
+ IF sy-subrc = 0.
+ r_style = ls_styles-guid.
+ ELSE.
+ CASE i_type.
+ WHEN c_type_hdr. " Header
+ lo_style = create_style_hdr( i_alignment = i_alignment ).
+ WHEN c_type_str. "Stripped
+ lo_style = create_style_stripped( i_alignment = i_alignment
+ i_inttype = i_inttype
+ i_decimals = i_decimals ).
+ WHEN c_type_nor. "Normal
+ lo_style = create_style_normal( i_alignment = i_alignment
+ i_inttype = i_inttype
+ i_decimals = i_decimals ).
+ WHEN c_type_sub. "Subtotals
+ lo_style = create_style_subtotal( i_alignment = i_alignment
+ i_inttype = i_inttype
+ i_decimals = i_decimals ).
+ WHEN c_type_tot. "Totals
+ lo_style = create_style_total( i_alignment = i_alignment
+ i_inttype = i_inttype
+ i_decimals = i_decimals ).
+ ENDCASE.
+ IF lo_style IS NOT INITIAL.
+ r_style = lo_style->get_guid( ).
+ ls_styles-type = i_type.
+ ls_styles-alignment = i_alignment.
+ ls_styles-inttype = i_inttype.
+ ls_styles-decimals = i_decimals.
+ ls_styles-guid = r_style.
+ ls_styles-style = lo_style.
+ INSERT ls_styles INTO TABLE wt_styles.
+ ENDIF.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD get_subclasses.
+ DATA:
+ lt_subclasses TYPE seor_inheritance_keys,
+ ls_subclass TYPE seor_inheritance_key,
+ lr_classdescr TYPE REF TO cl_abap_classdescr.
+
+ CALL FUNCTION 'SEO_CLASS_GET_ALL_SUBS'
+ EXPORTING
+ clskey = is_clskey
+ IMPORTING
+ inhkeys = lt_subclasses
+ EXCEPTIONS
+ class_not_existing = 1
+ OTHERS = 2.
+
+ CHECK sy-subrc = 0.
+
+ LOOP AT lt_subclasses INTO ls_subclass.
+ lr_classdescr ?= cl_abap_classdescr=>describe_by_name( ls_subclass-clsname ).
+ IF lr_classdescr->is_instantiatable( ) = abap_true.
+ APPEND ls_subclass TO ct_classes.
+ ENDIF.
+ ENDLOOP.
+ ENDMETHOD.
+
+
+ METHOD init_option.
+
+ ws_option-filter = abap_true.
+ ws_option-hidenc = abap_true.
+ ws_option-subtot = abap_true.
+
+ ENDMETHOD.
+
+
+ METHOD loop_normal.
+ DATA: l_row_int_end TYPE yecb_cell_row,
+ l_row_int TYPE yecb_cell_row,
+ l_col_int TYPE yecb_cell_column,
+ l_col_alpha TYPE yecb_cell_column_alpha,
+ l_cell_value TYPE yecb_cell_value,
+ l_s_color TYPE abap_bool,
+ lo_column TYPE REF TO ycl_ecb_column,
+ l_formula TYPE yecb_cell_formula,
+ l_style TYPE yecb_cell_style,
+ l_cells TYPE i,
+ l_count TYPE i,
+ l_table_row TYPE i.
+
+ FIELD-SYMBOLS: TYPE any,
+ TYPE STANDARD TABLE,
+ TYPE yecb_s_converter_fcat,
+ TYPE any.
+
+ ASSIGN wo_data->* TO .
+
+ DESCRIBE TABLE wt_fieldcatalog LINES l_cells.
+ DESCRIBE TABLE LINES l_count.
+ l_cells = l_cells * l_count.
+
+* It is better to loop column by column
+ LOOP AT wt_fieldcatalog ASSIGNING .
+ l_row_int = i_row_int.
+ l_col_int = i_col_int + -position - 1.
+
+* Freeze panes
+ IF -fix_column = abap_true.
+ ADD 1 TO r_freeze_col.
+ ENDIF.
+ l_s_color = abap_true.
+
+ l_col_alpha = ycl_ecb_common=>convert_column2alpha( l_col_int ).
+
+* Only if the Header is required create it.
+ IF ws_option-hidehd IS INITIAL.
+ " First of all write column header
+ l_cell_value = -scrtext_m.
+ wo_worksheet->set_cell( ip_column = l_col_alpha
+ ip_row = l_row_int
+ ip_value = l_cell_value
+ ip_style = -style_hdr ).
+ ADD 1 TO l_row_int.
+ ENDIF.
+ LOOP AT ASSIGNING .
+ l_table_row = sy-tabix.
+* Now the cell values
+ ASSIGN COMPONENT -columnname OF STRUCTURE TO .
+* Now let's write the cell values
+ IF ws_layout-is_stripped = abap_true AND l_s_color = abap_true.
+ l_style = get_color_style( i_row = l_table_row
+ i_fieldname = -columnname
+ i_style = -style_stripped ).
+ wo_worksheet->set_cell( ip_column = l_col_alpha
+ ip_row = l_row_int
+ ip_value =
+ ip_style = l_style
+ ip_conv_exit_length = ws_option-conv_exit_length ).
+ CLEAR l_s_color.
+ ELSE.
+ l_style = get_color_style( i_row = l_table_row
+ i_fieldname = -columnname
+ i_style = -style_normal ).
+ wo_worksheet->set_cell( ip_column = l_col_alpha
+ ip_row = l_row_int
+ ip_value =
+ ip_style = l_style
+ ip_conv_exit_length = ws_option-conv_exit_length ).
+ l_s_color = abap_true.
+ ENDIF.
+ READ TABLE wt_filter TRANSPORTING NO FIELDS WITH TABLE KEY rownumber = l_table_row
+ columnname = -columnname.
+ IF sy-subrc = 0.
+ wo_worksheet->get_cell( EXPORTING
+ ip_column = l_col_alpha
+ ip_row = l_row_int
+ IMPORTING
+ ep_value = l_cell_value ).
+ wo_autofilter->set_value( i_column = l_col_int
+ i_value = l_cell_value ).
+ ENDIF.
+ ADD 1 TO l_row_int.
+ ENDLOOP.
+* Now let's check for optimized
+ IF -is_optimized = abap_true .
+ lo_column = wo_worksheet->get_column( ip_column = l_col_alpha ).
+ lo_column->set_auto_size( ip_auto_size = abap_true ) .
+ ENDIF.
+* Now let's check for visible
+ IF -is_hidden = abap_true.
+ lo_column = wo_worksheet->get_column( ip_column = l_col_alpha ).
+ lo_column->set_visible( ip_visible = abap_false ) .
+ ENDIF.
+* Now let's check for total versus subtotal.
+ IF -totals_function IS NOT INITIAL.
+ l_row_int_end = l_row_int - 1.
+
+ l_formula = create_formular_total( i_row_int = l_row_int_end
+ i_column = l_col_alpha
+ i_totals_function = -totals_function ).
+ wo_worksheet->set_cell( ip_column = l_col_alpha
+ ip_row = l_row_int
+ ip_formula = l_formula
+ ip_style = -style_total ).
+ ENDIF.
+ ENDLOOP.
+ ENDMETHOD.
+
+
+ METHOD loop_subtotal.
+
+ DATA: l_row_int_start TYPE yecb_cell_row,
+ l_row_int_end TYPE yecb_cell_row,
+ l_row_int TYPE yecb_cell_row,
+ l_col_int TYPE yecb_cell_column,
+ l_col_alpha TYPE yecb_cell_column_alpha,
+ l_col_alpha_start TYPE yecb_cell_column_alpha,
+ l_cell_value TYPE yecb_cell_value,
+ l_s_color TYPE abap_bool,
+ lo_column TYPE REF TO ycl_ecb_column,
+ lo_row TYPE REF TO ycl_ecb_row,
+ l_formula TYPE yecb_cell_formula,
+ l_style TYPE yecb_cell_style,
+ l_text TYPE string,
+ ls_sort_values TYPE ts_sort_values,
+ ls_subtotal_rows TYPE ts_subtotal_rows,
+ l_sort_level TYPE int4,
+ l_hidden TYPE int4,
+ l_line TYPE i,
+ l_cells TYPE i,
+ l_count TYPE i,
+ l_table_row TYPE i,
+ lt_fcat TYPE yecb_t_converter_fcat.
+
+ FIELD-SYMBOLS: TYPE any,
+ TYPE STANDARD TABLE,
+ TYPE yecb_s_converter_fcat,
+ TYPE any,
+ TYPE any,
+ TYPE ts_sort_values.
+
+ ASSIGN wo_data->* TO .
+
+ CLEAR: wt_sort_values,
+ wt_subtotal_rows.
+
+ DESCRIBE TABLE wt_fieldcatalog LINES l_cells.
+ DESCRIBE TABLE LINES l_count.
+ l_cells = l_cells * l_count.
+
+ READ TABLE ASSIGNING INDEX 1.
+ IF sy-subrc = 0.
+ l_row_int = i_row_int + 1.
+ lt_fcat = wt_fieldcatalog.
+ SORT lt_fcat BY sort_level DESCENDING.
+ LOOP AT lt_fcat ASSIGNING WHERE is_subtotalled = abap_true.
+ ASSIGN COMPONENT -columnname OF STRUCTURE TO .
+ ls_sort_values-fieldname = -columnname.
+ ls_sort_values-row_int = l_row_int.
+ ls_sort_values-sort_level = -sort_level.
+ ls_sort_values-is_collapsed = -is_collapsed.
+ CREATE DATA ls_sort_values-value LIKE .
+ ASSIGN ls_sort_values-value->* TO .
+ = .
+ INSERT ls_sort_values INTO TABLE wt_sort_values.
+ ENDLOOP.
+ ENDIF.
+ l_row_int = i_row_int.
+* Let's check if we need to hide a sort level.
+ DESCRIBE TABLE wt_sort_values LINES l_line.
+ IF l_line <= 1.
+ CLEAR l_hidden.
+ ELSE.
+ LOOP AT wt_sort_values INTO ls_sort_values WHERE is_collapsed = abap_false.
+ IF l_hidden < ls_sort_values-sort_level.
+ l_hidden = ls_sort_values-sort_level.
+ ENDIF.
+ ENDLOOP.
+ ENDIF.
+ ADD 1 TO l_hidden. " As this is the first level we show.
+* First loop without formular only addtional rows with subtotal text.
+ LOOP AT ASSIGNING .
+ ADD 1 TO l_row_int. " 1 is for header row.
+ l_row_int_start = l_row_int.
+ SORT lt_fcat BY sort_level DESCENDING.
+ LOOP AT lt_fcat ASSIGNING WHERE is_subtotalled = abap_true.
+ l_col_int = i_col_int + -position - 1.
+ l_col_alpha = ycl_ecb_common=>convert_column2alpha( l_col_int ).
+* Now the cell values
+ ASSIGN COMPONENT -columnname OF STRUCTURE TO .
+ IF sy-subrc = 0.
+ READ TABLE wt_sort_values ASSIGNING WITH TABLE KEY fieldname = -columnname.
+ IF sy-subrc = 0.
+ ASSIGN -value->* TO .
+ IF <> OR -new = abap_true.
+* First let's remmember the subtotal values as it has to appear later.
+ ls_subtotal_rows-row_int = l_row_int.
+ ls_subtotal_rows-row_int_start = -row_int.
+ ls_subtotal_rows-columnname = -columnname.
+ INSERT ls_subtotal_rows INTO TABLE wt_subtotal_rows.
+* Now let's write the subtotal line
+ l_cell_value = create_text_subtotal( i_value =
+ i_totals_function = -totals_function ).
+ wo_worksheet->set_cell( ip_column = l_col_alpha
+ ip_row = l_row_int
+ ip_value = l_cell_value
+ ip_abap_type = cl_abap_typedescr=>typekind_string
+ ip_style = -style_subtotal ).
+ lo_row = wo_worksheet->get_row( ip_row = l_row_int ).
+ lo_row->set_outline_level( ip_outline_level = -sort_level ) .
+ IF -is_collapsed = abap_true.
+ IF -sort_level > l_hidden.
+ lo_row->set_visible( ip_visible = abap_false ) .
+ ENDIF.
+ lo_row->set_collapsed( ip_collapsed = -is_collapsed ) .
+ ENDIF.
+* Now let's change the key
+ ADD 1 TO l_row_int.
+ = .
+ -new = abap_false.
+ l_line = -sort_level.
+ LOOP AT wt_sort_values ASSIGNING WHERE sort_level >= l_line.
+ -row_int = l_row_int.
+ ENDLOOP.
+ ENDIF.
+ ENDIF.
+ ENDIF.
+ ENDLOOP.
+ ENDLOOP.
+ ADD 1 TO l_row_int.
+ l_row_int_start = l_row_int.
+ SORT lt_fcat BY sort_level DESCENDING.
+ LOOP AT lt_fcat ASSIGNING WHERE is_subtotalled = abap_true.
+ l_col_int = i_col_int + -position - 1.
+ l_col_alpha = ycl_ecb_common=>convert_column2alpha( l_col_int ).
+ READ TABLE wt_sort_values ASSIGNING WITH TABLE KEY fieldname =