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>
This commit is contained in:
Lars Hvam 2021-11-11 10:19:41 +01:00 committed by GitHub
parent ea40b6860e
commit fd83cbc112
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 236 additions and 163 deletions

View File

@ -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: <ls_font_cache> TYPE mty_s_font_cache,
<ls_font_metric> TYPE mty_s_font_metric,
<ls_itcfc> 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 <ls_font_cache>.
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 <ls_font_cache>.
" 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 <ls_itcfc>.
ld_uccp = <ls_itcfc>-cpcharno.
ls_font_metric-char =
cl_abap_conv_in_ce=>uccpi( ld_uccp ).
ls_font_metric-char_width = <ls_itcfc>-tdcwidths.
INSERT ls_font_metric
INTO TABLE <ls_font_cache>-th_font_metrics.
ENDLOOP.
ENDIF.
ENDIF.
" Calculate the cell width
" If available, use font metrics
IF lines( <ls_font_cache>-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 <ls_font_cache>-th_font_metrics
WITH TABLE KEY char = ld_current_character
ASSIGNING <ls_font_metric>.
IF sy-subrc = 0.
" The size of the letter is known
" -> Add the actual size of the letter
ADD <ls_font_metric>-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.

View File

@ -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.

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
<VSEOCLASS>
<CLSNAME>ZCL_EXCEL_FONT</CLSNAME>
<LANGU>E</LANGU>
<DESCRIPT>abap2xlsx - Font Logic</DESCRIPT>
<STATE>1</STATE>
<CLSCCINCL>X</CLSCCINCL>
<FIXPT>X</FIXPT>
<UNICODE>X</UNICODE>
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
</VSEOCLASS>
</asx:values>
</asx:abap>
</abapGit>

View File

@ -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: <ls_font_cache> TYPE mty_s_font_cache,
<ls_font_metric> TYPE mty_s_font_metric,
<ls_itcfc> 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 <ls_font_cache>.
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 <ls_font_cache>.
" 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 <ls_itcfc>.
ld_uccp = <ls_itcfc>-cpcharno.
ls_font_metric-char =
cl_abap_conv_in_ce=>uccpi( ld_uccp ).
ls_font_metric-char_width = <ls_itcfc>-tdcwidths.
INSERT ls_font_metric
INTO TABLE <ls_font_cache>-th_font_metrics.
ENDLOOP.
ENDIF.
ENDIF.
" Calculate the cell width
" If available, use font metrics
IF lines( <ls_font_cache>-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 <ls_font_cache>-th_font_metrics
WITH TABLE KEY char = ld_current_character
ASSIGNING <ls_font_metric>.
IF sy-subrc = 0.
" The size of the letter is known
" -> Add the actual size of the letter
ADD <ls_font_metric>-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.

View File

@ -753,12 +753,6 @@
<LANGU>E</LANGU>
<DESCRIPT>Pagebreaks</DESCRIPT>
</SEOCOMPOTX>
<SEOCOMPOTX>
<CLSNAME>ZCL_EXCEL_WORKSHEET</CLSNAME>
<CMPNAME>MTH_FONT_CACHE</CMPNAME>
<LANGU>E</LANGU>
<DESCRIPT>Hash table containing fonts and their metrics</DESCRIPT>
</SEOCOMPOTX>
<SEOCOMPOTX>
<CLSNAME>ZCL_EXCEL_WORKSHEET</CLSNAME>
<CMPNAME>MTY_MERGE</CMPNAME>