From 79d0df4dc364e7719faebfca397b4554b64882fc Mon Sep 17 00:00:00 2001 From: sandraros <34005250+sandraros@users.noreply.github.com> Date: Sat, 15 Jan 2022 19:19:14 +0100 Subject: [PATCH] BIND_TABLE incorrect table overlap check (#964) * draft, not finished * Final commit Co-authored-by: sandraros Co-authored-by: Abo --- src/zcl_excel_worksheet.clas.abap | 186 ++++++++---- src/zcl_excel_worksheet.clas.testclasses.abap | 287 ++++++++++++++++++ 2 files changed, 408 insertions(+), 65 deletions(-) diff --git a/src/zcl_excel_worksheet.clas.abap b/src/zcl_excel_worksheet.clas.abap index 7311994..f368db4 100644 --- a/src/zcl_excel_worksheet.clas.abap +++ b/src/zcl_excel_worksheet.clas.abap @@ -668,6 +668,7 @@ CLASS zcl_excel_worksheet DEFINITION *"* private components of class ZCL_EXCEL_WORKSHEET *"* do not include other source files here!!! + TYPES ty_table_settings TYPE STANDARD TABLE OF zexcel_s_table_settings WITH DEFAULT KEY. DATA active_cell TYPE zexcel_s_cell_data . DATA charts TYPE REF TO zcl_excel_drawings . DATA columns TYPE REF TO zcl_excel_columns . @@ -706,6 +707,14 @@ CLASS zcl_excel_worksheet DEFINITION VALUE(ep_width) TYPE f RAISING zcx_excel . + CLASS-METHODS calculate_table_bottom_right + IMPORTING + ip_table TYPE STANDARD TABLE + it_field_catalog TYPE zexcel_t_fieldcatalog + CHANGING + cs_settings TYPE zexcel_s_table_settings + RAISING + zcx_excel. CLASS-METHODS check_cell_column_formula IMPORTING it_column_formulas TYPE mty_th_column_formula @@ -724,6 +733,12 @@ CLASS zcl_excel_worksheet DEFINITION !ct_rtf TYPE zexcel_t_rtf RAISING zcx_excel . + CLASS-METHODS check_table_overlapping + IMPORTING + is_table_settings TYPE zexcel_s_table_settings + it_other_table_settings TYPE ty_table_settings + RAISING + zcx_excel. METHODS clear_initial_colorxfields IMPORTING is_color TYPE zexcel_s_style_color @@ -927,30 +942,24 @@ CLASS zcl_excel_worksheet IMPLEMENTATION. lc_top_left_row TYPE zexcel_cell_row VALUE 1. DATA: - lv_row_int TYPE zexcel_cell_row, - lv_first_row TYPE zexcel_cell_row, - lv_last_row TYPE zexcel_cell_row, - lv_column_int TYPE zexcel_cell_column, - lv_column_alpha TYPE zexcel_cell_column_alpha, - lt_field_catalog TYPE zexcel_t_fieldcatalog, - lv_id TYPE i, - lv_rows TYPE i, - lv_formula TYPE string, - ls_settings TYPE zexcel_s_table_settings, - lo_table TYPE REF TO zcl_excel_table, - lt_column_name_buffer TYPE SORTED TABLE OF string WITH UNIQUE KEY table_line, - lv_value TYPE string, - lv_value_lowercase TYPE string, - lv_syindex TYPE c LENGTH 3, - lv_errormessage TYPE string, "ins issue #237 - - lv_columns TYPE i, - lt_columns TYPE zexcel_t_fieldcatalog, - lv_maxcol TYPE i, - lv_maxrow TYPE i, - lo_iterator TYPE REF TO zcl_excel_collection_iterator, - lo_style_cond TYPE REF TO zcl_excel_style_cond, - lo_curtable TYPE REF TO zcl_excel_table. + lv_row_int TYPE zexcel_cell_row, + lv_first_row TYPE zexcel_cell_row, + lv_last_row TYPE zexcel_cell_row, + lv_column_int TYPE zexcel_cell_column, + lv_column_alpha TYPE zexcel_cell_column_alpha, + lt_field_catalog TYPE zexcel_t_fieldcatalog, + lv_id TYPE i, + lv_formula TYPE string, + ls_settings TYPE zexcel_s_table_settings, + lo_table TYPE REF TO zcl_excel_table, + lt_column_name_buffer TYPE SORTED TABLE OF string WITH UNIQUE KEY table_line, + lv_value TYPE string, + lv_value_lowercase TYPE string, + lv_syindex TYPE c LENGTH 3, + lo_iterator TYPE REF TO zcl_excel_collection_iterator, + lo_style_cond TYPE REF TO zcl_excel_style_cond, + lo_curtable TYPE REF TO zcl_excel_table, + lt_other_table_settings TYPE ty_table_settings. DATA: ls_column_formula TYPE mty_s_column_formula, lv_mincol TYPE i. @@ -982,50 +991,26 @@ CLASS zcl_excel_worksheet IMPLEMENTATION. SORT lt_field_catalog BY position. -*--------------------------------------------------------------------* -* issue #237 Check if overlapping areas exist Start -*--------------------------------------------------------------------* - "Get the number of columns for the current table - lt_columns = lt_field_catalog. - DELETE lt_columns WHERE dynpfld NE abap_true. - DESCRIBE TABLE lt_columns LINES lv_columns. + calculate_table_bottom_right( + EXPORTING + ip_table = ip_table + it_field_catalog = lt_field_catalog + CHANGING + cs_settings = ls_settings ). - "Calculate the top left row of the current table - lv_column_int = zcl_excel_common=>convert_column2int( ls_settings-top_left_column ). - lv_row_int = ls_settings-top_left_row. - - "Get number of row for the current table - DESCRIBE TABLE ip_table LINES lv_rows. - - "Calculate the bottom right row for the current table - lv_maxcol = lv_column_int + lv_columns - 1. - lv_maxrow = lv_row_int + lv_rows - 1. - ls_settings-bottom_right_column = zcl_excel_common=>convert_column2alpha( lv_maxcol ). - ls_settings-bottom_right_row = lv_maxrow. - - lv_column_int = zcl_excel_common=>convert_column2int( ls_settings-top_left_column ). +* Check if overlapping areas exist lo_iterator = me->tables->get_iterator( ). WHILE lo_iterator->has_next( ) EQ abap_true. - lo_curtable ?= lo_iterator->get_next( ). - IF ( ( ls_settings-top_left_row GE lo_curtable->settings-top_left_row AND ls_settings-top_left_row LE lo_curtable->settings-bottom_right_row ) - OR - ( ls_settings-bottom_right_row GE lo_curtable->settings-top_left_row AND ls_settings-bottom_right_row LE lo_curtable->settings-bottom_right_row ) - ) - AND - ( ( lv_column_int GE zcl_excel_common=>convert_column2int( lo_curtable->settings-top_left_column ) AND lv_column_int LE zcl_excel_common=>convert_column2int( lo_curtable->settings-bottom_right_column ) ) - OR - ( lv_maxcol GE zcl_excel_common=>convert_column2int( lo_curtable->settings-top_left_column ) AND lv_maxcol LE zcl_excel_common=>convert_column2int( lo_curtable->settings-bottom_right_column ) ) - ). - lv_errormessage = 'Table overlaps with previously bound table and will not be added to worksheet.'(400). - zcx_excel=>raise_text( lv_errormessage ). - ENDIF. - + APPEND lo_curtable->settings TO lt_other_table_settings. ENDWHILE. -*--------------------------------------------------------------------* -* issue #237 Check if overlapping areas exist End -*--------------------------------------------------------------------* + + check_table_overlapping( + is_table_settings = ls_settings + it_other_table_settings = lt_other_table_settings ). + +* Start filling the table CREATE OBJECT lo_table. lo_table->settings = ls_settings. @@ -1035,6 +1020,8 @@ CLASS zcl_excel_worksheet IMPLEMENTATION. me->tables->add( lo_table ). + lv_column_int = zcl_excel_common=>convert_column2int( ls_settings-top_left_column ). + lv_row_int = ls_settings-top_left_row. * It is better to loop column by column (only visible column) LOOP AT lt_field_catalog ASSIGNING WHERE dynpfld EQ abap_true. @@ -1113,7 +1100,7 @@ CLASS zcl_excel_worksheet IMPLEMENTATION. ls_column_formula-table_top_left_row = lo_table->settings-top_left_row. ls_column_formula-table_bottom_right_row = lo_table->settings-bottom_right_row. ls_column_formula-table_left_column_int = lv_mincol. - ls_column_formula-table_right_column_int = lv_maxcol. + ls_column_formula-table_right_column_int = zcl_excel_common=>convert_column2int( lo_table->settings-bottom_right_column ). INSERT ls_column_formula INTO TABLE column_formulas. ENDIF. @@ -1233,7 +1220,7 @@ CLASS zcl_excel_worksheet IMPLEMENTATION. *--------------------------------------------------------------------* IF -style_cond IS NOT INITIAL. lv_first_row = ls_settings-top_left_row + 1. " +1 to exclude header - lv_last_row = ls_settings-top_left_row + lv_rows. + lv_last_row = ls_settings-bottom_right_row. lo_style_cond = me->get_style_cond( -style_cond ). lo_style_cond->set_range( ip_start_column = lv_column_alpha ip_start_row = lv_first_row @@ -1254,7 +1241,7 @@ CLASS zcl_excel_worksheet IMPLEMENTATION. IF ip_table IS INITIAL. es_table_settings-bottom_right_row = ls_settings-top_left_row + 2. "Last rows ELSE. - es_table_settings-bottom_right_row = ls_settings-top_left_row + lv_rows + 1. "Last rows + es_table_settings-bottom_right_row = ls_settings-bottom_right_row + 1. "Last rows ENDIF. " << Issue #291 @@ -1445,6 +1432,40 @@ CLASS zcl_excel_worksheet IMPLEMENTATION. ENDMETHOD. "CALCULATE_COLUMN_WIDTHS + METHOD calculate_table_bottom_right. + + DATA: lv_errormessage TYPE string, + lv_columns TYPE i, + lt_columns TYPE zexcel_t_fieldcatalog, + lv_maxrow TYPE i, + lo_iterator TYPE REF TO zcl_excel_collection_iterator, + lo_curtable TYPE REF TO zcl_excel_table, + lv_row_int TYPE zexcel_cell_row, + lv_column_int TYPE zexcel_cell_column, + lv_rows TYPE i, + lv_maxcol TYPE i. + + "Get the number of columns for the current table + lt_columns = it_field_catalog. + DELETE lt_columns WHERE dynpfld NE abap_true. + DESCRIBE TABLE lt_columns LINES lv_columns. + + "Calculate the top left row of the current table + lv_column_int = zcl_excel_common=>convert_column2int( cs_settings-top_left_column ). + lv_row_int = cs_settings-top_left_row. + + "Get number of row for the current table + DESCRIBE TABLE ip_table LINES lv_rows. + + "Calculate the bottom right row for the current table + lv_maxcol = lv_column_int + lv_columns - 1. + lv_maxrow = lv_row_int + lv_rows. + cs_settings-bottom_right_column = zcl_excel_common=>convert_column2alpha( lv_maxcol ). + cs_settings-bottom_right_row = lv_maxrow. + + ENDMETHOD. + + METHOD change_area_style. DATA: lv_row TYPE zexcel_cell_row, @@ -1939,6 +1960,41 @@ CLASS zcl_excel_worksheet IMPLEMENTATION. ENDMETHOD. + METHOD check_table_overlapping. + + DATA: lv_errormessage TYPE string, + lv_column_int TYPE zexcel_cell_column, + lv_maxcol TYPE i. + FIELD-SYMBOLS: + TYPE zexcel_s_table_settings. + + lv_column_int = zcl_excel_common=>convert_column2int( is_table_settings-top_left_column ). + lv_maxcol = zcl_excel_common=>convert_column2int( is_table_settings-bottom_right_column ). + + LOOP AT it_other_table_settings ASSIGNING . + + IF ( ( is_table_settings-top_left_row GE -top_left_row + AND is_table_settings-top_left_row LE -bottom_right_row ) + OR + ( is_table_settings-bottom_right_row GE -top_left_row + AND is_table_settings-bottom_right_row LE -bottom_right_row ) + ) + AND + ( ( lv_column_int GE zcl_excel_common=>convert_column2int( -top_left_column ) + AND lv_column_int LE zcl_excel_common=>convert_column2int( -bottom_right_column ) ) + OR + ( lv_maxcol GE zcl_excel_common=>convert_column2int( -top_left_column ) + AND lv_maxcol LE zcl_excel_common=>convert_column2int( -bottom_right_column ) ) + ). + lv_errormessage = 'Table overlaps with previously bound table and will not be added to worksheet.'(400). + zcx_excel=>raise_text( lv_errormessage ). + ENDIF. + + ENDLOOP. + + ENDMETHOD. + + METHOD class_constructor. c_messages-formula_id_only_is_possible = |{ 'If Formula ID is used, value and formula must be empty'(008) }|. diff --git a/src/zcl_excel_worksheet.clas.testclasses.abap b/src/zcl_excel_worksheet.clas.testclasses.abap index 0de93c6..cce06df 100644 --- a/src/zcl_excel_worksheet.clas.testclasses.abap +++ b/src/zcl_excel_worksheet.clas.testclasses.abap @@ -1,10 +1,14 @@ CLASS ltc_normalize_columnrow_param DEFINITION DEFERRED. CLASS ltc_normalize_range_param DEFINITION DEFERRED. +CLASS ltc_calculate_table_bottom_rig DEFINITION DEFERRED. CLASS ltc_normalize_style_param DEFINITION DEFERRED. CLASS ltc_check_cell_column_formula DEFINITION DEFERRED. +CLASS ltc_check_overlapping DEFINITION DEFERRED. CLASS zcl_excel_worksheet DEFINITION LOCAL FRIENDS ltc_normalize_columnrow_param ltc_normalize_range_param + ltc_calculate_table_bottom_rig + ltc_check_overlapping ltc_normalize_style_param ltc_check_cell_column_formula. @@ -27,6 +31,25 @@ CLASS lcl_excel_worksheet_test DEFINITION FOR TESTING ENDCLASS. "lcl_Excel_Worksheet_Test +CLASS ltc_calculate_table_bottom_rig DEFINITION FOR TESTING + RISK LEVEL HARMLESS + DURATION SHORT. + + PRIVATE SECTION. + + METHODS: + simple FOR TESTING RAISING cx_static_check, + empty_table FOR TESTING RAISING cx_static_check, + column_not_selected FOR TESTING RAISING cx_static_check. + + DATA: + test_table TYPE TABLE OF string, + field_catalog TYPE zexcel_t_fieldcatalog, + field_catalog_line TYPE zexcel_s_fieldcatalog, + table_settings TYPE zexcel_s_table_settings. "class under test + +ENDCLASS. + CLASS ltc_check_cell_column_formula DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. @@ -61,6 +84,42 @@ CLASS ltc_check_cell_column_formula DEFINITION FOR TESTING ENDCLASS. +CLASS ltc_check_overlapping DEFINITION FOR TESTING + RISK LEVEL HARMLESS + DURATION SHORT. + + PRIVATE SECTION. + TYPES : BEGIN OF ty_parameters, + BEGIN OF input, + table_settings TYPE zexcel_s_table_settings, + other_table_settings TYPE zcl_excel_worksheet=>ty_table_settings, + END OF input, + BEGIN OF output, + fails TYPE abap_bool, + END OF output, + END OF ty_parameters. + DATA: table_1_settings TYPE zexcel_s_table_settings. + + METHODS: + no_overlap_top FOR TESTING RAISING cx_static_check, + no_overlap_left FOR TESTING RAISING cx_static_check, + no_overlap_bottom FOR TESTING RAISING cx_static_check, + no_overlap_right FOR TESTING RAISING cx_static_check, + overlap_top FOR TESTING RAISING cx_static_check, + overlap_left FOR TESTING RAISING cx_static_check, + overlap_bottom FOR TESTING RAISING cx_static_check, + overlap_right FOR TESTING RAISING cx_static_check. + + METHODS setup. + METHODS assert + IMPORTING + input TYPE ty_parameters-input + exp TYPE ty_parameters-output + RAISING + cx_static_check. +ENDCLASS. + + CLASS ltc_normalize_columnrow_param DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. @@ -564,6 +623,85 @@ CLASS lcl_excel_worksheet_test IMPLEMENTATION. ENDCLASS. "lcl_Excel_Worksheet_Test +CLASS ltc_calculate_table_bottom_rig IMPLEMENTATION. + + METHOD simple. + + APPEND INITIAL LINE TO test_table. + APPEND INITIAL LINE TO test_table. + + field_catalog_line-dynpfld = abap_true. + field_catalog_line-fieldname = 'COL1'. + APPEND field_catalog_line TO field_catalog. + field_catalog_line-dynpfld = abap_true. + field_catalog_line-fieldname = 'COL2'. + APPEND field_catalog_line TO field_catalog. + + table_settings-top_left_column = 'A'. + table_settings-top_left_row = '1'. + + zcl_excel_worksheet=>calculate_table_bottom_right( + EXPORTING + ip_table = test_table + it_field_catalog = field_catalog + CHANGING + cs_settings = table_settings ). + + cl_abap_unit_assert=>assert_equals( act = table_settings-bottom_right_column exp = 'B' ). + cl_abap_unit_assert=>assert_equals( act = table_settings-bottom_right_row exp = 3 ). + + ENDMETHOD. + + METHOD empty_table. + + field_catalog_line-dynpfld = abap_true. + field_catalog_line-fieldname = 'COL1'. + APPEND field_catalog_line TO field_catalog. + + table_settings-top_left_column = 'B'. + table_settings-top_left_row = '2'. + + zcl_excel_worksheet=>calculate_table_bottom_right( + EXPORTING + ip_table = test_table + it_field_catalog = field_catalog + CHANGING + cs_settings = table_settings ). + + cl_abap_unit_assert=>assert_equals( act = table_settings-bottom_right_column exp = 'B' ). + cl_abap_unit_assert=>assert_equals( act = table_settings-bottom_right_row exp = 2 ). + + ENDMETHOD. + + METHOD column_not_selected. + + APPEND INITIAL LINE TO test_table. + + field_catalog_line-dynpfld = abap_true. + field_catalog_line-fieldname = 'COL1'. + APPEND field_catalog_line TO field_catalog. + field_catalog_line-dynpfld = abap_false. + field_catalog_line-fieldname = 'COL2'. + APPEND field_catalog_line TO field_catalog. + + table_settings-top_left_column = 'B'. + table_settings-top_left_row = '2'. + + zcl_excel_worksheet=>calculate_table_bottom_right( + EXPORTING + ip_table = test_table + it_field_catalog = field_catalog + CHANGING + cs_settings = table_settings ). + + cl_abap_unit_assert=>assert_equals( act = table_settings-bottom_right_column exp = 'B' ). + cl_abap_unit_assert=>assert_equals( act = table_settings-bottom_right_row exp = 3 ). + + ENDMETHOD. + +ENDCLASS. + + CLASS ltc_check_cell_column_formula IMPLEMENTATION. METHOD setup. @@ -661,6 +799,155 @@ CLASS ltc_check_cell_column_formula IMPLEMENTATION. ENDCLASS. +CLASS ltc_check_overlapping IMPLEMENTATION. + + METHOD setup. + + table_1_settings-top_left_column = 'C'. + table_1_settings-top_left_row = 3. + table_1_settings-bottom_right_column = 'D'. + table_1_settings-bottom_right_row = 4. + + ENDMETHOD. + + METHOD no_overlap_top. + DATA: input TYPE ty_parameters-input, + exp TYPE ty_parameters-output. + + input-table_settings-top_left_column = 'C'. + input-table_settings-top_left_row = 1. + input-table_settings-bottom_right_column = 'D'. + input-table_settings-bottom_right_row = 2. + APPEND table_1_settings TO input-other_table_settings. + exp-fails = abap_false. + assert( input = input exp = exp ). + + ENDMETHOD. + + METHOD no_overlap_left. + DATA: input TYPE ty_parameters-input, + exp TYPE ty_parameters-output. + + input-table_settings-top_left_column = 'A'. + input-table_settings-top_left_row = 3. + input-table_settings-bottom_right_column = 'B'. + input-table_settings-bottom_right_row = 4. + APPEND table_1_settings TO input-other_table_settings. + exp-fails = abap_false. + assert( input = input exp = exp ). + + ENDMETHOD. + + METHOD no_overlap_bottom. + DATA: input TYPE ty_parameters-input, + exp TYPE ty_parameters-output. + + input-table_settings-top_left_column = 'C'. + input-table_settings-top_left_row = 5. + input-table_settings-bottom_right_column = 'D'. + input-table_settings-bottom_right_row = 6. + APPEND table_1_settings TO input-other_table_settings. + exp-fails = abap_false. + assert( input = input exp = exp ). + + ENDMETHOD. + + METHOD no_overlap_right. + DATA: input TYPE ty_parameters-input, + exp TYPE ty_parameters-output. + + input-table_settings-top_left_column = 'E'. + input-table_settings-top_left_row = 3. + input-table_settings-bottom_right_column = 'F'. + input-table_settings-bottom_right_row = 4. + APPEND table_1_settings TO input-other_table_settings. + exp-fails = abap_false. + assert( input = input exp = exp ). + + ENDMETHOD. + + METHOD overlap_top. + DATA: input TYPE ty_parameters-input, + exp TYPE ty_parameters-output. + + input-table_settings-top_left_column = 'C'. + input-table_settings-top_left_row = 2. + input-table_settings-bottom_right_column = 'D'. + input-table_settings-bottom_right_row = 3. + APPEND table_1_settings TO input-other_table_settings. + exp-fails = abap_true. + assert( input = input exp = exp ). + + ENDMETHOD. + + METHOD overlap_left. + DATA: input TYPE ty_parameters-input, + exp TYPE ty_parameters-output. + + input-table_settings-top_left_column = 'B'. + input-table_settings-top_left_row = 3. + input-table_settings-bottom_right_column = 'C'. + input-table_settings-bottom_right_row = 4. + APPEND table_1_settings TO input-other_table_settings. + exp-fails = abap_true. + assert( input = input exp = exp ). + + ENDMETHOD. + + METHOD overlap_bottom. + DATA: input TYPE ty_parameters-input, + exp TYPE ty_parameters-output. + + input-table_settings-top_left_column = 'C'. + input-table_settings-top_left_row = 4. + input-table_settings-bottom_right_column = 'D'. + input-table_settings-bottom_right_row = 5. + APPEND table_1_settings TO input-other_table_settings. + exp-fails = abap_true. + assert( input = input exp = exp ). + + ENDMETHOD. + + METHOD overlap_right. + DATA: input TYPE ty_parameters-input, + exp TYPE ty_parameters-output. + + input-table_settings-top_left_column = 'D'. + input-table_settings-top_left_row = 3. + input-table_settings-bottom_right_column = 'E'. + input-table_settings-bottom_right_row = 4. + APPEND table_1_settings TO input-other_table_settings. + exp-fails = abap_true. + assert( input = input exp = exp ). + + ENDMETHOD. + + METHOD assert. + DATA: error TYPE REF TO zcx_excel. + FIELD-SYMBOLS: + TYPE STANDARD TABLE. + + TRY. + + zcl_excel_worksheet=>check_table_overlapping( + is_table_settings = input-table_settings + it_other_table_settings = input-other_table_settings ). + IF exp-fails = abap_true. + cl_abap_unit_assert=>fail( msg = 'Overlap exists, exception was expected' ). + ENDIF. + + CATCH zcx_excel INTO error. + IF exp-fails = abap_false. + RAISE EXCEPTION error. + ENDIF. + RETURN. + ENDTRY. + + ENDMETHOD. + +ENDCLASS. + + CLASS ltc_normalize_columnrow_param IMPLEMENTATION. METHOD setup.