From fd83cbc1123d1fd81671bd65a3680f4b3fba6b27 Mon Sep 17 00:00:00 2001 From: Lars Hvam Date: Thu, 11 Nov 2021 10:19:41 +0100 Subject: [PATCH] extract font width logic to new class (#882) * extract font width logic to new class * rename importing parameters * fixes * Update src/zcl_excel_font.clas.abap Co-authored-by: sandraros <34005250+sandraros@users.noreply.github.com> * Update src/zcl_excel_font.clas.abap Co-authored-by: sandraros <34005250+sandraros@users.noreply.github.com> * Update src/zcl_excel_worksheet.clas.abap Co-authored-by: sandraros <34005250+sandraros@users.noreply.github.com> * Update src/zcl_excel_font.clas.testclasses.abap Co-authored-by: sandraros <34005250+sandraros@users.noreply.github.com> * Update src/zcl_excel_font.clas.abap Co-authored-by: sandraros <34005250+sandraros@users.noreply.github.com> * fix syntax * Update src/zcl_excel_font.clas.abap Co-authored-by: sandraros <34005250+sandraros@users.noreply.github.com> Co-authored-by: sandraros <34005250+sandraros@users.noreply.github.com> --- src/zcl_excel_font.clas.abap | 183 +++++++++++++++++++++++ src/zcl_excel_font.clas.testclasses.abap | 27 ++++ src/zcl_excel_font.clas.xml | 17 +++ src/zcl_excel_worksheet.clas.abap | 166 ++------------------ src/zcl_excel_worksheet.clas.xml | 6 - 5 files changed, 236 insertions(+), 163 deletions(-) create mode 100644 src/zcl_excel_font.clas.abap create mode 100644 src/zcl_excel_font.clas.testclasses.abap create mode 100644 src/zcl_excel_font.clas.xml diff --git a/src/zcl_excel_font.clas.abap b/src/zcl_excel_font.clas.abap new file mode 100644 index 0000000..ceaeea1 --- /dev/null +++ b/src/zcl_excel_font.clas.abap @@ -0,0 +1,183 @@ +CLASS zcl_excel_font DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + + TYPES: + BEGIN OF mty_s_font_metric, + char TYPE c LENGTH 1, + char_width TYPE tdcwidths, + END OF mty_s_font_metric . + TYPES: + mty_th_font_metrics + TYPE HASHED TABLE OF mty_s_font_metric + WITH UNIQUE KEY char . + TYPES: + BEGIN OF mty_s_font_cache, + font_name TYPE zexcel_style_font_name, + font_height TYPE tdfontsize, + flag_bold TYPE abap_bool, + flag_italic TYPE abap_bool, + th_font_metrics TYPE mty_th_font_metrics, + END OF mty_s_font_cache . + TYPES: + mty_th_font_cache + TYPE HASHED TABLE OF mty_s_font_cache + WITH UNIQUE KEY font_name font_height flag_bold flag_italic . + + CONSTANTS lc_default_font_height TYPE tdfontsize VALUE '110' ##NO_TEXT. + CONSTANTS lc_default_font_name TYPE zexcel_style_font_name VALUE 'Calibri' ##NO_TEXT. + CLASS-DATA mth_font_cache TYPE mty_th_font_cache . + + CLASS-METHODS calculate_text_width + IMPORTING + !iv_font_name TYPE zexcel_style_font_name + !iv_font_height TYPE tdfontsize + !iv_flag_bold TYPE abap_bool + !iv_flag_italic TYPE abap_bool + !iv_cell_value TYPE zexcel_cell_value + RETURNING + VALUE(rv_width) TYPE float . + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + + +CLASS ZCL_EXCEL_FONT IMPLEMENTATION. + + + METHOD calculate_text_width. + + CONSTANTS lc_excel_cell_padding TYPE float VALUE '0.75'. + + DATA: ld_current_character TYPE c LENGTH 1, + lt_itcfc TYPE STANDARD TABLE OF itcfc, + ld_offset TYPE i, + ld_length TYPE i, + ld_uccp TYPE i, + ls_font_metric TYPE mty_s_font_metric, + ld_width_from_font_metrics TYPE i, + ld_font_family TYPE itcfh-tdfamily, + lt_font_families LIKE STANDARD TABLE OF ld_font_family, + ls_font_cache TYPE mty_s_font_cache. + + FIELD-SYMBOLS: TYPE mty_s_font_cache, + TYPE mty_s_font_metric, + TYPE itcfc. + + " Check if the same font (font name and font attributes) was already + " used before + READ TABLE mth_font_cache + WITH TABLE KEY + font_name = iv_font_name + font_height = iv_font_height + flag_bold = iv_flag_bold + flag_italic = iv_flag_italic + ASSIGNING . + + IF sy-subrc <> 0. + " Font is used for the first time + " Add the font to our local font cache + ls_font_cache-font_name = iv_font_name. + ls_font_cache-font_height = iv_font_height. + ls_font_cache-flag_bold = iv_flag_bold. + ls_font_cache-flag_italic = iv_flag_italic. + INSERT ls_font_cache INTO TABLE mth_font_cache + ASSIGNING . + + " Determine the SAPscript font family name from the Excel + " font name + SELECT tdfamily + FROM tfo01 + INTO TABLE lt_font_families + UP TO 1 ROWS + WHERE tdtext = iv_font_name + ORDER BY PRIMARY KEY. + + " Check if a matching font family was found + " Fonts can be uploaded from TTF files using transaction SE73 + IF lines( lt_font_families ) > 0. + READ TABLE lt_font_families INDEX 1 INTO ld_font_family. + + " Load font metrics (returns a table with the size of each letter + " in the font) + CALL FUNCTION 'LOAD_FONT' + EXPORTING + family = ld_font_family + height = iv_font_height + printer = 'SWIN' + bold = iv_flag_bold + italic = iv_flag_italic + TABLES + metric = lt_itcfc + EXCEPTIONS + font_family = 1 + codepage = 2 + device_type = 3 + OTHERS = 4. + IF sy-subrc <> 0. + CLEAR lt_itcfc. + ENDIF. + + " For faster access, convert each character number to the actual + " character, and store the characters and their sizes in a hash + " table + LOOP AT lt_itcfc ASSIGNING . + ld_uccp = -cpcharno. + ls_font_metric-char = + cl_abap_conv_in_ce=>uccpi( ld_uccp ). + ls_font_metric-char_width = -tdcwidths. + INSERT ls_font_metric + INTO TABLE -th_font_metrics. + ENDLOOP. + + ENDIF. + ENDIF. + + " Calculate the cell width + " If available, use font metrics + IF lines( -th_font_metrics ) = 0. + " Font metrics are not available + " -> Calculate the cell width using only the font size + ld_length = strlen( iv_cell_value ). + rv_width = ld_length * iv_font_height / lc_default_font_height + lc_excel_cell_padding. + + ELSE. + " Font metrics are available + + " Calculate the size of the text by adding the sizes of each + " letter + ld_length = strlen( iv_cell_value ). + DO ld_length TIMES. + " Subtract 1, because the first character is at offset 0 + ld_offset = sy-index - 1. + + " Read the current character from the cell value + ld_current_character = iv_cell_value+ld_offset(1). + + " Look up the size of the current letter + READ TABLE -th_font_metrics + WITH TABLE KEY char = ld_current_character + ASSIGNING . + IF sy-subrc = 0. + " The size of the letter is known + " -> Add the actual size of the letter + ADD -char_width TO ld_width_from_font_metrics. + ELSE. + " The size of the letter is unknown + " -> Add the font height as the default letter size + ADD iv_font_height TO ld_width_from_font_metrics. + ENDIF. + ENDDO. + + " Add cell padding (Excel makes columns a bit wider than the space + " that is needed for the text itself) and convert unit + " (division by 100) + rv_width = ld_width_from_font_metrics / 100 + lc_excel_cell_padding. + ENDIF. + + ENDMETHOD. +ENDCLASS. diff --git a/src/zcl_excel_font.clas.testclasses.abap b/src/zcl_excel_font.clas.testclasses.abap new file mode 100644 index 0000000..9801cec --- /dev/null +++ b/src/zcl_excel_font.clas.testclasses.abap @@ -0,0 +1,27 @@ +CLASS ltcl_Test DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS FINAL. + + PRIVATE SECTION. + METHODS calculate FOR TESTING RAISING cx_static_check. +ENDCLASS. + + +CLASS ltcl_Test IMPLEMENTATION. + + METHOD calculate. + + DATA lv_width TYPE f. + + lv_width = zcl_excel_font=>calculate_text_width( + iv_font_name = 'foobar' + iv_font_height = 20 + iv_flag_bold = abap_false + iv_flag_italic = abap_false + iv_cell_value = 'hello world' ). + + cl_abap_unit_assert=>assert_equals( + act = lv_width + exp = '2.75' ). + + ENDMETHOD. + +ENDCLASS. diff --git a/src/zcl_excel_font.clas.xml b/src/zcl_excel_font.clas.xml new file mode 100644 index 0000000..d846847 --- /dev/null +++ b/src/zcl_excel_font.clas.xml @@ -0,0 +1,17 @@ + + + + + + ZCL_EXCEL_FONT + E + abap2xlsx - Font Logic + 1 + X + X + X + X + + + + diff --git a/src/zcl_excel_worksheet.clas.abap b/src/zcl_excel_worksheet.clas.abap index 4941db1..ef0e86b 100644 --- a/src/zcl_excel_worksheet.clas.abap +++ b/src/zcl_excel_worksheet.clas.abap @@ -620,30 +620,6 @@ CLASS zcl_excel_worksheet DEFINITION PROTECTED SECTION. PRIVATE SECTION. - TYPES: - BEGIN OF mty_s_font_metric, - char TYPE c LENGTH 1, - char_width TYPE tdcwidths, - END OF mty_s_font_metric . - TYPES: - mty_th_font_metrics - TYPE HASHED TABLE OF mty_s_font_metric - WITH UNIQUE KEY char . - TYPES: - BEGIN OF mty_s_font_cache, - font_name TYPE zexcel_style_font_name, - font_height TYPE tdfontsize, - flag_bold TYPE abap_bool, - flag_italic TYPE abap_bool, - th_font_metrics TYPE mty_th_font_metrics, - END OF mty_s_font_cache . - TYPES: - mty_th_font_cache - TYPE HASHED TABLE OF mty_s_font_cache - WITH UNIQUE KEY font_name font_height flag_bold flag_italic . -* types: -* mty_ts_row_dimension TYPE SORTED TABLE OF zexcel_s_worksheet_rowdimensio WITH UNIQUE KEY row . - *"* private components of class ZCL_EXCEL_WORKSHEET *"* do not include other source files here!!! DATA active_cell TYPE zexcel_s_cell_data . @@ -663,7 +639,6 @@ CLASS zcl_excel_worksheet DEFINITION DATA hyperlinks TYPE REF TO cl_object_collection . DATA lower_cell TYPE zexcel_s_cell_data . DATA mo_pagebreaks TYPE REF TO zcl_excel_worksheet_pagebreaks . - CLASS-DATA mth_font_cache TYPE mty_th_font_cache . DATA mt_row_outlines TYPE mty_ts_outlines_row . DATA print_title_col_from TYPE zexcel_cell_column_alpha . DATA print_title_col_to TYPE zexcel_cell_column_alpha . @@ -1222,13 +1197,7 @@ CLASS ZCL_EXCEL_WORKSHEET IMPLEMENTATION. * - Add cell padding to simulate Excel behavior *--------------------------------------------------------------------* - CONSTANTS: - lc_default_font_name TYPE zexcel_style_font_name VALUE 'Calibri', "#EC NOTEXT - lc_default_font_height TYPE tdfontsize VALUE '110', - lc_excel_cell_padding TYPE float VALUE '0.75'. - DATA: ld_cell_value TYPE zexcel_cell_value, - ld_current_character TYPE c LENGTH 1, ld_style_guid TYPE zexcel_cell_style, ls_stylemapping TYPE zexcel_s_stylemapping, lo_table_object TYPE REF TO object, @@ -1240,21 +1209,8 @@ CLASS ZCL_EXCEL_WORKSHEET IMPLEMENTATION. ld_flag_italic TYPE abap_bool VALUE abap_false, ld_date TYPE d, ld_date_char TYPE c LENGTH 50, - ld_font_height TYPE tdfontsize VALUE lc_default_font_height, - lt_itcfc TYPE STANDARD TABLE OF itcfc, - ld_offset TYPE i, - ld_length TYPE i, - ld_uccp TYPE i, - ls_font_metric TYPE mty_s_font_metric, - ld_width_from_font_metrics TYPE i, - ld_font_family TYPE itcfh-tdfamily, - ld_font_name TYPE zexcel_style_font_name VALUE lc_default_font_name, - lt_font_families LIKE STANDARD TABLE OF ld_font_family, - ls_font_cache TYPE mty_s_font_cache. - - FIELD-SYMBOLS: TYPE mty_s_font_cache, - TYPE mty_s_font_metric, - TYPE itcfc. + ld_font_height TYPE tdfontsize VALUE zcl_excel_font=>lc_default_font_height, + ld_font_name TYPE zexcel_style_font_name VALUE zcl_excel_font=>lc_default_font_name. " Determine cell content and cell style me->get_cell( EXPORTING ip_column = ip_column @@ -1340,116 +1296,12 @@ CLASS ZCL_EXCEL_WORKSHEET IMPLEMENTATION. ENDTRY. ENDIF. - " Check if the same font (font name and font attributes) was already - " used before - READ TABLE mth_font_cache - WITH TABLE KEY - font_name = ld_font_name - font_height = ld_font_height - flag_bold = ld_flag_bold - flag_italic = ld_flag_italic - ASSIGNING . - - IF sy-subrc <> 0. - " Font is used for the first time - " Add the font to our local font cache - ls_font_cache-font_name = ld_font_name. - ls_font_cache-font_height = ld_font_height. - ls_font_cache-flag_bold = ld_flag_bold. - ls_font_cache-flag_italic = ld_flag_italic. - INSERT ls_font_cache INTO TABLE mth_font_cache - ASSIGNING . - - " Determine the SAPscript font family name from the Excel - " font name - SELECT tdfamily - FROM tfo01 - INTO TABLE lt_font_families - UP TO 1 ROWS - WHERE tdtext = ld_font_name - ORDER BY PRIMARY KEY. - - " Check if a matching font family was found - " Fonts can be uploaded from TTF files using transaction SE73 - IF lines( lt_font_families ) > 0. - READ TABLE lt_font_families INDEX 1 INTO ld_font_family. - - " Load font metrics (returns a table with the size of each letter - " in the font) - CALL FUNCTION 'LOAD_FONT' - EXPORTING - family = ld_font_family - height = ld_font_height - printer = 'SWIN' - bold = ld_flag_bold - italic = ld_flag_italic - TABLES - metric = lt_itcfc - EXCEPTIONS - font_family = 1 - codepage = 2 - device_type = 3 - OTHERS = 4. - IF sy-subrc <> 0. - CLEAR lt_itcfc. - ENDIF. - - " For faster access, convert each character number to the actual - " character, and store the characters and their sizes in a hash - " table - LOOP AT lt_itcfc ASSIGNING . - ld_uccp = -cpcharno. - ls_font_metric-char = - cl_abap_conv_in_ce=>uccpi( ld_uccp ). - ls_font_metric-char_width = -tdcwidths. - INSERT ls_font_metric - INTO TABLE -th_font_metrics. - ENDLOOP. - - ENDIF. - ENDIF. - - " Calculate the cell width - " If available, use font metrics - IF lines( -th_font_metrics ) = 0. - " Font metrics are not available - " -> Calculate the cell width using only the font size - ld_length = strlen( ld_cell_value ). - ep_width = ld_length * ld_font_height / lc_default_font_height + lc_excel_cell_padding. - - ELSE. - " Font metrics are available - - " Calculate the size of the text by adding the sizes of each - " letter - ld_length = strlen( ld_cell_value ). - DO ld_length TIMES. - " Subtract 1, because the first character is at offset 0 - ld_offset = sy-index - 1. - - " Read the current character from the cell value - ld_current_character = ld_cell_value+ld_offset(1). - - " Look up the size of the current letter - READ TABLE -th_font_metrics - WITH TABLE KEY char = ld_current_character - ASSIGNING . - IF sy-subrc = 0. - " The size of the letter is known - " -> Add the actual size of the letter - ADD -char_width TO ld_width_from_font_metrics. - ELSE. - " The size of the letter is unknown - " -> Add the font height as the default letter size - ADD ld_font_height TO ld_width_from_font_metrics. - ENDIF. - ENDDO. - - " Add cell padding (Excel makes columns a bit wider than the space - " that is needed for the text itself) and convert unit - " (division by 100) - ep_width = ld_width_from_font_metrics / 100 + lc_excel_cell_padding. - ENDIF. + ep_width = zcl_excel_font=>calculate_text_width( + iv_font_name = ld_font_name + iv_font_height = ld_font_height + iv_flag_bold = ld_flag_bold + iv_flag_italic = ld_flag_italic + iv_cell_value = ld_cell_value ). " If the current cell contains an auto filter, make it a bit wider. " The size used by the auto filter button does not depend on the font @@ -1458,7 +1310,7 @@ CLASS ZCL_EXCEL_WORKSHEET IMPLEMENTATION. ADD 2 TO ep_width. ENDIF. - ENDMETHOD. "CALCULATE_CELL_WIDTH + ENDMETHOD. METHOD calculate_column_widths. diff --git a/src/zcl_excel_worksheet.clas.xml b/src/zcl_excel_worksheet.clas.xml index 50df7e0..a9bcd5e 100644 --- a/src/zcl_excel_worksheet.clas.xml +++ b/src/zcl_excel_worksheet.clas.xml @@ -753,12 +753,6 @@ E Pagebreaks - - ZCL_EXCEL_WORKSHEET - MTH_FONT_CACHE - E - Hash table containing fonts and their metrics - ZCL_EXCEL_WORKSHEET MTY_MERGE