diff --git a/ZA2X/CLAS/ZCL_EXCEL_WORKSHEET.slnk b/ZA2X/CLAS/ZCL_EXCEL_WORKSHEET.slnk index e1b08c1..104915d 100644 --- a/ZA2X/CLAS/ZCL_EXCEL_WORKSHEET.slnk +++ b/ZA2X/CLAS/ZCL_EXCEL_WORKSHEET.slnk @@ -1,5 +1,26 @@ + + + + @@ -214,6 +235,7 @@ ENDCLASS. "lcl_gui_alv_grid DEFINITION + @@ -2860,31 +2882,255 @@ ENDCLASS. "lcl_gui_alv_grid DEFINITION - + - method CALCULATE_CELL_WIDTH. - DATA: cell_value TYPE zexcel_cell_value, - guid TYPE zexcel_cell_style, - stylemapping TYPE zexcel_s_stylemapping. + *--------------------------------------------------------------------* +* issue #293 - Roberto Bianco +* - Christian Assig 2014-03-14 +* +* changes: - Calculate widths using SAPscript font metrics +* (transaction SE73) +* - Calculate the width of dates +* - Add additional width for auto filter buttons +* - Add cell padding to simulate Excel behavior +*--------------------------------------------------------------------* +METHOD calculate_cell_width. - me->get_cell( EXPORTING ip_column = ip_column " Cell Column - ip_row = ip_row " Cell Row - IMPORTING ep_value = cell_value - ep_guid = guid )." Cell Value ). + 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, + lo_table TYPE REF TO zcl_excel_table, + ld_table_top_left_column TYPE zexcel_cell_column, + ld_table_bottom_right_column TYPE zexcel_cell_column, + ld_flag_contains_auto_filter TYPE abap_bool VALUE abap_false, + ld_flag_bold TYPE abap_bool VALUE abap_false, + 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_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. - ep_width = STRLEN( cell_value ). - TRY. - stylemapping = me->excel->get_style_to_guid( guid ). - CATCH zcx_excel. - EXIT. " Do nothing if no style was found - ENDTRY. + FIELD-SYMBOLS: <ls_font_cache> TYPE mty_s_font_cache, + <ls_font_metric> TYPE mty_s_font_metric, + <ls_itcfc> TYPE itcfc. - IF stylemapping-complete_stylex-font-size = 'X'. - ep_width = ep_width * stylemapping-complete_style-font-size / 11. + " Determine cell content and cell style + me->get_cell( EXPORTING ip_column = ip_column + ip_row = ip_row + IMPORTING ep_value = ld_cell_value + ep_guid = ld_style_guid ). + + " ABAP2XLSX uses tables to define areas containing headers and + " auto-filters. Find out if the current cell is in the header + " of one of these tables. + LOOP AT me->tables->collection INTO lo_table_object. + " Downcast: OBJECT -> ZCL_EXCEL_TABLE + lo_table ?= lo_table_object. + + " Convert column letters to corresponding integer values + ld_table_top_left_column = + zcl_excel_common=>convert_column2int( + lo_table->settings-top_left_column ). + + ld_table_bottom_right_column = + zcl_excel_common=>convert_column2int( + lo_table->settings-bottom_right_column ). + + " Is the current cell part of the table header? + IF ip_column BETWEEN ld_table_top_left_column AND + ld_table_bottom_right_column AND + ip_row EQ lo_table->settings-top_left_row. + " Current cell is part of the table header + " -> Assume that an auto filter is present and that the font is + " bold + ld_flag_contains_auto_filter = abap_true. + ld_flag_bold = abap_true. + ENDIF. + ENDLOOP. + + " If a style GUID is present, read style attributes + IF ld_style_guid IS NOT INITIAL. + TRY. + " Read style attributes + ls_stylemapping = me->excel->get_style_to_guid( ld_style_guid ). + + " If the current cell contains the default date format, + " convert the cell value to a date and calculate its length + IF ls_stylemapping-complete_style-number_format-format_code = + zcl_excel_style_number_format=>c_format_date_std. + + " Convert excel date to ABAP date + ld_date = + zcl_excel_common=>excel_string_to_date( ld_cell_value ). + + " Format ABAP date using user's formatting settings + WRITE ld_date TO ld_date_char. + + " Remember the formatted date to calculate the cell size + ld_cell_value = ld_date_char. + + ENDIF. + + " Read the font size and convert it to the font height + " used by SAPscript (multiplication by 10) + IF ls_stylemapping-complete_stylex-font-size = abap_true. + ld_font_height = ls_stylemapping-complete_style-font-size * 10. + ENDIF. + + " If set, remember the font name + IF ls_stylemapping-complete_stylex-font-name = abap_true. + ld_font_name = ls_stylemapping-complete_style-font-name. + ENDIF. + + " If set, remember whether font is bold and italic. + IF ls_stylemapping-complete_stylex-font-bold = abap_true. + ld_flag_bold = ls_stylemapping-complete_style-font-bold. + ENDIF. + + IF ls_stylemapping-complete_stylex-font-italic = abap_true. + ld_flag_italic = ls_stylemapping-complete_style-font-italic. + ENDIF. + + CATCH zcx_excel ##NO_HANDLER. + " Style GUID is present, but style was not found + " Continue with default values + + ENDTRY. ENDIF. - endmethod. + " 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. + + " 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 + ep_width = + strlen( ld_cell_value ) * 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 + DO strlen( ld_cell_value ) 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. + + " 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 + " size. + IF ld_flag_contains_auto_filter = abap_true. + ADD 2 TO ep_width. + ENDIF. + +ENDMETHOD. @@ -2906,7 +3152,7 @@ ENDCLASS. "lcl_gui_alv_grid DEFINITION DATA: cell_style TYPE REF TO zcl_excel_style. DATA: count TYPE int4. DATA: highest_row TYPE int4. - DATA: width TYPE i. + DATA: width TYPE float. FIELD-SYMBOLS: <column_dimension> LIKE LINE OF column_dimensions. FIELD-SYMBOLS: <auto_size> LIKE LINE OF auto_sizes.