diff --git a/src/zcl_excel_writer_2007.clas.abap b/src/zcl_excel_writer_2007.clas.abap index 45f47c6..b59b3db 100644 --- a/src/zcl_excel_writer_2007.clas.abap +++ b/src/zcl_excel_writer_2007.clas.abap @@ -4224,7 +4224,11 @@ CLASS zcl_excel_writer_2007 IMPLEMENTATION. bottom TYPE i, END OF lty_table_area. - CONSTANTS: lc_dummy_cell_content TYPE zexcel_s_cell_data-cell_value VALUE '})~~~ This is a dummy value for ABAP2XLSX and you should never find this in a real excelsheet Ihope'. + TYPES: BEGIN OF lty_row_data, + row TYPE zexcel_cell_row, + tabix_to TYPE sy-tabix, + hidden_only TYPE abap_bool, + END OF lty_row_data. CONSTANTS: lc_xml_node_sheetdata TYPE string VALUE 'sheetData', " SheetData tag lc_xml_node_row TYPE string VALUE 'row', " Row tag @@ -4239,6 +4243,7 @@ CLASS zcl_excel_writer_2007 IMPLEMENTATION. DATA: col_count TYPE int4, lo_autofilters TYPE REF TO zcl_excel_autofilters, lo_autofilter TYPE REF TO zcl_excel_autofilter, + ls_area TYPE zexcel_s_autofilter_area, lo_iterator TYPE REF TO zcl_excel_collection_iterator, lo_table TYPE REF TO zcl_excel_table, @@ -4246,19 +4251,18 @@ CLASS zcl_excel_writer_2007 IMPLEMENTATION. ls_table_area LIKE LINE OF lt_table_areas, lo_column TYPE REF TO zcl_excel_column, + ls_row_data TYPE lty_row_data, + lt_sorted_rows LIKE SORTED TABLE OF ls_row_data WITH UNIQUE KEY row, ls_sheet_content LIKE LINE OF io_worksheet->sheet_content, - ls_sheet_content_empty LIKE LINE OF io_worksheet->sheet_content, lv_current_row TYPE i, - lv_next_row TYPE i, - lv_last_row TYPE i, + lv_cell_tabix TYPE sy-tabix, * lts_row_dimensions TYPE zexcel_t_worksheet_rowdimensio, lo_row_iterator TYPE REF TO zcl_excel_collection_iterator, lo_row TYPE REF TO zcl_excel_row, - lo_row_empty TYPE REF TO zcl_excel_row, lts_row_outlines TYPE zcl_excel_worksheet=>mty_ts_outlines_row, + ls_row_outline LIKE LINE OF lts_row_outlines, - ls_last_row TYPE zexcel_s_cell_data, ls_style_mapping TYPE zexcel_s_styles_mapping, lo_element_2 TYPE REF TO if_ixml_element, @@ -4270,8 +4274,7 @@ CLASS zcl_excel_writer_2007 IMPLEMENTATION. DATA: lt_column_formulas_used TYPE mty_column_formulas_used, lv_si TYPE i. - FIELD-SYMBOLS: TYPE zexcel_s_cell_data, - LIKE LINE OF lts_row_outlines. + FIELD-SYMBOLS: TYPE zexcel_s_cell_data. " sheetData node @@ -4284,8 +4287,8 @@ CLASS zcl_excel_writer_2007 IMPLEMENTATION. lo_autofilters = excel->get_autofilters_reference( ). lo_autofilter = lo_autofilters->get( io_worksheet = io_worksheet ) . IF lo_autofilter IS BOUND. -* Area not used here, but makes the validation for lo_autofilter->is_row_hidden - lo_autofilter->get_filter_area( ) . +* Makes the validation for lo_autofilter->is_row_hidden, too + ls_area = lo_autofilter->get_filter_area( ) . ENDIF. *--------------------------------------------------------------------* *issue #220 - If cell in tables-area don't use default from row or column or sheet - Coding 1 - start @@ -4303,254 +4306,249 @@ CLASS zcl_excel_writer_2007 IMPLEMENTATION. *--------------------------------------------------------------------* *issue #220 - If cell in tables-area don't use default from row or column or sheet - Coding 1 - end *--------------------------------------------------------------------* -*We have problems when the first rows or trailing rows are not set but we have rowinformation -*to solve this we add dummycontent into first and last line that will not be set -*Set first line if necessary - READ TABLE io_worksheet->sheet_content TRANSPORTING NO FIELDS WITH KEY cell_row = 1. - IF sy-subrc <> 0. - ls_sheet_content_empty-cell_row = 1. - ls_sheet_content_empty-cell_column = 1. - ls_sheet_content_empty-cell_value = lc_dummy_cell_content. - INSERT ls_sheet_content_empty INTO TABLE io_worksheet->sheet_content. - ENDIF. -*Set last line if necessary -*Last row with cell content - lv_last_row = io_worksheet->get_highest_row( ). -*Last line with row-information set directly ( like line height, hidden-status ... ) +* Preparing the row loop +* First of all get the rows with cell content + LOOP AT io_worksheet->sheet_content INTO ls_sheet_content. + AT END OF cell_row. + ls_row_data-row = ls_sheet_content-cell_row. + ls_row_data-tabix_to = sy-tabix. + INSERT ls_row_data INTO TABLE lt_sorted_rows. + ENDAT. + ENDLOOP. + IF sy-subrc = 0. +* Get first cell data to start the WHILE loop below + lv_cell_tabix = 1. + READ TABLE io_worksheet->sheet_content ASSIGNING INDEX lv_cell_tabix. + CLEAR ls_row_data-tabix_to. "not set for next preparations + ENDIF. + +* Get every row with relevant data lo_row_iterator = io_worksheet->get_rows_iterator( ). WHILE lo_row_iterator->has_next( ) = abap_true. lo_row ?= lo_row_iterator->get_next( ). - IF lo_row->get_row_index( ) > lv_last_row. - lv_last_row = lo_row->get_row_index( ). - ENDIF. +* It is intended not to pass io_worksheet to the three concerning methods. Outline +* rows are collected next. Therefore it is sufficiently done in the main row loop. + CHECK lo_row->get_row_height( ) >= 0 OR + lo_row->get_collapsed( ) = abap_true OR + lo_row->get_outline_level( ) > 0 OR + lo_row->get_xf_index( ) <> 0 OR + lo_row->get_visible( ) = abap_false. + ls_row_data-row = lo_row->get_row_index( ). + INSERT ls_row_data INTO TABLE lt_sorted_rows. ENDWHILE. -*Last line with row-information set indirectly by row outline +* Get every outline row to set outline level lts_row_outlines = io_worksheet->get_row_outlines( ). - LOOP AT lts_row_outlines ASSIGNING . - IF -collapsed = 'X'. - lv_current_row = -row_to + 1. " collapsed-status may be set on following row - ELSE. - lv_current_row = -row_to. " collapsed-status may be set on following row - ENDIF. - IF lv_current_row > lv_last_row. - lv_last_row = lv_current_row. + LOOP AT lts_row_outlines INTO ls_row_outline. + IF ls_row_outline-collapsed = abap_true. +* And include the line of the collapsed-status Symbol (+) shown below/above + IF io_worksheet->zif_excel_sheet_properties~summarybelow = zif_excel_sheet_properties=>c_below_on. + ADD 1 TO ls_row_outline-row_to. " collapsed-status set on following row + ELSEIF ls_row_outline-row_from > 1. + SUBTRACT 1 FROM ls_row_outline-row_from. " collapsed-status set on previous row + ENDIF. ENDIF. + lv_current_row = ls_row_outline-row_from. + WHILE lv_current_row <= ls_row_outline-row_to. + ls_row_data-row = lv_current_row. + INSERT ls_row_data INTO TABLE lt_sorted_rows. + ADD 1 TO lv_current_row. + ENDWHILE. ENDLOOP. - READ TABLE io_worksheet->sheet_content TRANSPORTING NO FIELDS WITH KEY cell_row = lv_last_row. - IF sy-subrc <> 0. - ls_sheet_content_empty-cell_row = lv_last_row. - ls_sheet_content_empty-cell_column = 1. - ls_sheet_content_empty-cell_value = lc_dummy_cell_content. - INSERT ls_sheet_content_empty INTO TABLE io_worksheet->sheet_content. + +* Last of all preparations + IF lo_autofilter IS BOUND. + ls_row_data-hidden_only = abap_true. + lv_current_row = ls_area-row_start + 1. "without header + WHILE lv_current_row <= ls_area-row_end. + READ TABLE lt_sorted_rows TRANSPORTING NO FIELDS + WITH TABLE KEY row = lv_current_row. + IF sy-subrc <> 0 AND + lo_autofilter->is_row_hidden( lv_current_row ) = abap_true. + ls_row_data-row = lv_current_row. + INSERT ls_row_data INTO TABLE lt_sorted_rows. + ENDIF. + ADD 1 TO lv_current_row. + ENDWHILE. ENDIF. - CLEAR ls_sheet_content. - LOOP AT io_worksheet->sheet_content INTO ls_sheet_content. - CLEAR ls_style_mapping. -*Create row element -*issues #346,#154, #195 - problems when we have information in row_dimension but no cell content in that row -*Get next line that may have to be added. If we have empty lines this is the next line after previous cell content -*Otherwise it is the line of the current cell content - lv_current_row = ls_last_row-cell_row + 1. - IF lv_current_row > ls_sheet_content-cell_row. - lv_current_row = ls_sheet_content-cell_row. - ENDIF. -*Fill in empty lines if necessary - assign an emtpy sheet content - lv_next_row = lv_current_row. - WHILE lv_next_row <= ls_sheet_content-cell_row. - lv_current_row = lv_next_row. - lv_next_row = lv_current_row + 1. - IF lv_current_row = ls_sheet_content-cell_row. " cell value found in this row - ASSIGN ls_sheet_content TO . - ELSE. -*Check if empty row is really necessary - this is basically the case when we have information in row_dimension - lo_row_empty = io_worksheet->get_row( lv_current_row ). - CHECK lo_row_empty->get_row_height( ) >= 0 OR - lo_row_empty->get_collapsed( io_worksheet ) = abap_true OR - lo_row_empty->get_outline_level( io_worksheet ) > 0 OR - lo_row_empty->get_xf_index( ) <> 0. - " Dummyentry A1 - ls_sheet_content_empty-cell_row = lv_current_row. - ls_sheet_content_empty-cell_column = 1. - ASSIGN ls_sheet_content_empty TO . - ENDIF. - - IF ls_last_row-cell_row NE -cell_row. - IF ls_last_row-cell_row IS NOT INITIAL. - " Row visibility of previos row. - IF lo_row->get_visible( io_worksheet ) = abap_false OR - ( lo_autofilter IS BOUND AND - lo_autofilter->is_row_hidden( ls_last_row-cell_row ) = abap_true ). - lo_element_2->set_attribute_ns( name = 'hidden' value = 'true' ). - ENDIF. - rv_ixml_sheet_data_root->append_child( new_child = lo_element_2 ). " row node - ENDIF. - " Add new row - lo_element_2 = io_document->create_simple_element( name = lc_xml_node_row - parent = io_document ). - " r - lv_value = -cell_row. - SHIFT lv_value RIGHT DELETING TRAILING space. - SHIFT lv_value LEFT DELETING LEADING space. - - lo_element_2->set_attribute_ns( name = lc_xml_attr_r - value = lv_value ). - " Spans - lv_value = col_count. - CONCATENATE '1:' lv_value INTO lv_value. - SHIFT lv_value RIGHT DELETING TRAILING space. - SHIFT lv_value LEFT DELETING LEADING space. - lo_element_2->set_attribute_ns( name = lc_xml_attr_spans - value = lv_value ). - lo_row = io_worksheet->get_row( -cell_row ). - " Row dimensions - IF lo_row->get_custom_height( ) = abap_true. - lo_element_2->set_attribute_ns( name = 'customHeight' value = '1' ). - ENDIF. - IF lo_row->get_row_height( ) > 0. - lv_value = lo_row->get_row_height( ). - lo_element_2->set_attribute_ns( name = 'ht' value = lv_value ). - ENDIF. - " Collapsed - IF lo_row->get_collapsed( io_worksheet ) = abap_true. - lo_element_2->set_attribute_ns( name = 'collapsed' value = 'true' ). - ENDIF. - " Outline level - IF lo_row->get_outline_level( io_worksheet ) > 0. - lv_value = lo_row->get_outline_level( io_worksheet ). - SHIFT lv_value RIGHT DELETING TRAILING space. - SHIFT lv_value LEFT DELETING LEADING space. - lo_element_2->set_attribute_ns( name = 'outlineLevel' value = lv_value ). - ENDIF. - " Style - IF lo_row->get_xf_index( ) <> 0. - lv_value = lo_row->get_xf_index( ). - lo_element_2->set_attribute_ns( name = 's' value = lv_value ). - lo_element_2->set_attribute_ns( name = 'customFormat' value = '1' ). - ENDIF. - ELSE. - - ENDIF. - ENDWHILE. - - lo_element_3 = io_document->create_simple_element( name = lc_xml_node_c +* Main row loop + LOOP AT lt_sorted_rows INTO ls_row_data. + " Add new row + lo_element_2 = io_document->create_simple_element( name = lc_xml_node_row parent = io_document ). + " r + lv_value = ls_row_data-row. + SHIFT lv_value RIGHT DELETING TRAILING space. + SHIFT lv_value LEFT DELETING LEADING space. - lo_element_3->set_attribute_ns( name = lc_xml_attr_r - value = -cell_coords ). + lo_element_2->set_attribute_ns( name = lc_xml_attr_r + value = lv_value ). + " Spans + lv_value = col_count. + CONCATENATE '1:' lv_value INTO lv_value. + SHIFT lv_value RIGHT DELETING TRAILING space. + SHIFT lv_value LEFT DELETING LEADING space. + lo_element_2->set_attribute_ns( name = lc_xml_attr_spans + value = lv_value ). + IF ls_row_data-hidden_only = abap_false. + lo_row = io_worksheet->get_row( ls_row_data-row ). + " Row dimensions + IF lo_row->get_custom_height( ) = abap_true. + lo_element_2->set_attribute_ns( name = 'customHeight' value = '1' ). + ENDIF. + IF lo_row->get_row_height( ) > 0. + lv_value = lo_row->get_row_height( ). + lo_element_2->set_attribute_ns( name = 'ht' value = lv_value ). + ENDIF. + " Collapsed + IF lo_row->get_collapsed( io_worksheet ) = abap_true. + lo_element_2->set_attribute_ns( name = 'collapsed' value = 'true' ). + ENDIF. + " Outline level + IF lo_row->get_outline_level( io_worksheet ) > 0. + lv_value = lo_row->get_outline_level( io_worksheet ). + SHIFT lv_value RIGHT DELETING TRAILING space. + SHIFT lv_value LEFT DELETING LEADING space. + lo_element_2->set_attribute_ns( name = 'outlineLevel' value = lv_value ). + ENDIF. + " Style + IF lo_row->get_xf_index( ) <> 0. + lv_value = lo_row->get_xf_index( ). + lo_element_2->set_attribute_ns( name = 's' value = lv_value ). + lo_element_2->set_attribute_ns( name = 'customFormat' value = '1' ). + ENDIF. + " Row visibility or row hidden by autofilter + IF lo_row->get_visible( io_worksheet ) = abap_false OR + ( lo_autofilter IS BOUND AND + lo_autofilter->is_row_hidden( ls_row_data-row ) = abap_true ). + lo_element_2->set_attribute_ns( name = 'hidden' value = 'true' ). + ENDIF. + ELSE. + lo_element_2->set_attribute_ns( name = 'hidden' value = 'true' ). + ENDIF. + + IF ls_row_data-tabix_to > 0. +* Of course the WHILE loop corresponds to +* LOOP AT io_worksheet->sheet_content ASSIGNING WHERE cell_row = ls_row_data-row. +* but it should be faster this way by benefiting the consecutive loop order + WHILE lv_cell_tabix <= ls_row_data-tabix_to. + lo_element_3 = io_document->create_simple_element( name = lc_xml_node_c + parent = io_document ). + + lo_element_3->set_attribute_ns( name = lc_xml_attr_r + value = -cell_coords ). *begin of change issue #157 - allow column cellstyle *if no cellstyle is set, look into column, then into sheet - IF -cell_style IS NOT INITIAL. - lv_style_guid = -cell_style. - ELSE. + IF -cell_style IS NOT INITIAL. + lv_style_guid = -cell_style. + ELSE. *--------------------------------------------------------------------* *issue #220 - If cell in tables-area don't use default from row or column or sheet - Coding 2 - start *--------------------------------------------------------------------* *Check if cell in any of the table areas - LOOP AT lt_table_areas TRANSPORTING NO FIELDS WHERE top <= -cell_row - AND bottom >= -cell_row - AND left <= -cell_column - AND right >= -cell_column. "#EC CI_SORTSEQ - EXIT. - ENDLOOP. - IF sy-subrc = 0. - CLEAR lv_style_guid. " No style --> EXCEL will use built-in-styles as declared in the tables-section - ELSE. + LOOP AT lt_table_areas TRANSPORTING NO FIELDS WHERE top <= -cell_row + AND bottom >= -cell_row + AND left <= -cell_column + AND right >= -cell_column. "#EC CI_SORTSEQ + EXIT. + ENDLOOP. + IF sy-subrc = 0. + CLEAR lv_style_guid. " No style --> EXCEL will use built-in-styles as declared in the tables-section + ELSE. + *--------------------------------------------------------------------* *issue #220 - If cell in tables-area don't use default from row or column or sheet - Coding 2 - end *--------------------------------------------------------------------* - lv_style_guid = io_worksheet->zif_excel_sheet_properties~get_style( ). - lo_column ?= io_worksheet->get_column( -cell_column ). - IF lo_column->get_column_index( ) = -cell_column. - lv_style_guid = lo_column->get_column_style_guid( ). - IF lv_style_guid IS INITIAL. lv_style_guid = io_worksheet->zif_excel_sheet_properties~get_style( ). - ENDIF. - ENDIF. + lo_column ?= io_worksheet->get_column( -cell_column ). + IF lo_column->get_column_index( ) = -cell_column. + lv_style_guid = lo_column->get_column_style_guid( ). + IF lv_style_guid IS INITIAL. + lv_style_guid = io_worksheet->zif_excel_sheet_properties~get_style( ). + ENDIF. + ENDIF. *--------------------------------------------------------------------* *issue #220 - If cell in tables-area don't use default from row or column or sheet - Coding 3 - start *--------------------------------------------------------------------* - ENDIF. + ENDIF. *--------------------------------------------------------------------* *issue #220 - If cell in tables-area don't use default from row or column or sheet - Coding 3 - end *--------------------------------------------------------------------* - ENDIF. - IF lv_style_guid IS NOT INITIAL. - READ TABLE styles_mapping INTO ls_style_mapping WITH KEY guid = lv_style_guid. -*end of change issue #157 - allow column cellstyles - lv_value = ls_style_mapping-style. - SHIFT lv_value RIGHT DELETING TRAILING space. - SHIFT lv_value LEFT DELETING LEADING space. - lo_element_3->set_attribute_ns( name = lc_xml_attr_s - value = lv_value ). - ENDIF. - - " For cells with formula ignore the value - Excel will calculate it - IF -cell_formula IS NOT INITIAL. - " fomula node - lo_element_4 = io_document->create_simple_element( name = lc_xml_node_f - parent = io_document ). - lo_element_4->set_value( value = -cell_formula ). - lo_element_3->append_child( new_child = lo_element_4 ). " formula node - ELSEIF -column_formula_id <> 0. - create_xl_sheet_column_formula( - EXPORTING - io_document = io_document - it_column_formulas = io_worksheet->column_formulas - is_sheet_content = - IMPORTING - eo_element = lo_element_4 - CHANGING - ct_column_formulas_used = lt_column_formulas_used - cv_si = lv_si ). - lo_element_3->append_child( new_child = lo_element_4 ). - ELSEIF -cell_value IS NOT INITIAL "cell can have just style or formula - AND -cell_value <> lc_dummy_cell_content. - IF -data_type IS NOT INITIAL. - IF -data_type EQ 's_leading_blanks'. - lo_element_3->set_attribute_ns( name = lc_xml_attr_t - value = 's' ). - ELSE. - lo_element_3->set_attribute_ns( name = lc_xml_attr_t - value = -data_type ). ENDIF. - ENDIF. + IF lv_style_guid IS NOT INITIAL. + CLEAR ls_style_mapping. + READ TABLE styles_mapping INTO ls_style_mapping WITH KEY guid = lv_style_guid. +*end of change issue #157 - allow column cellstyles + lv_value = ls_style_mapping-style. + SHIFT lv_value RIGHT DELETING TRAILING space. + SHIFT lv_value LEFT DELETING LEADING space. + lo_element_3->set_attribute_ns( name = lc_xml_attr_s + value = lv_value ). + ENDIF. - " value node - lo_element_4 = io_document->create_simple_element( name = lc_xml_node_v - parent = io_document ). + " For cells with formula ignore the value - Excel will calculate it + IF -cell_formula IS NOT INITIAL. + " fomula node + lo_element_4 = io_document->create_simple_element( name = lc_xml_node_f + parent = io_document ). + lo_element_4->set_value( value = -cell_formula ). + lo_element_3->append_child( new_child = lo_element_4 ). " formula node + ELSEIF -column_formula_id <> 0. + create_xl_sheet_column_formula( + EXPORTING + io_document = io_document + it_column_formulas = io_worksheet->column_formulas + is_sheet_content = + IMPORTING + eo_element = lo_element_4 + CHANGING + ct_column_formulas_used = lt_column_formulas_used + cv_si = lv_si ). + lo_element_3->append_child( new_child = lo_element_4 ). + ELSEIF -cell_value IS NOT INITIAL. "cell can have just style or formula + IF -data_type IS NOT INITIAL. + IF -data_type EQ 's_leading_blanks'. + lo_element_3->set_attribute_ns( name = lc_xml_attr_t + value = 's' ). + ELSE. + lo_element_3->set_attribute_ns( name = lc_xml_attr_t + value = -data_type ). + ENDIF. + ENDIF. - IF -data_type EQ 's' OR -data_type EQ 's_leading_blanks'. - lv_value = me->get_shared_string_index( ip_cell_value = -cell_value - it_rtf = -rtf_tab ). - CONDENSE lv_value. - lo_element_4->set_value( value = lv_value ). - ELSE. - lv_value = -cell_value. - CONDENSE lv_value. - lo_element_4->set_value( value = lv_value ). - ENDIF. + " value node + lo_element_4 = io_document->create_simple_element( name = lc_xml_node_v + parent = io_document ). - lo_element_3->append_child( new_child = lo_element_4 ). " value node + IF -data_type EQ 's' OR -data_type EQ 's_leading_blanks'. + lv_value = me->get_shared_string_index( ip_cell_value = -cell_value + it_rtf = -rtf_tab ). + CONDENSE lv_value. + lo_element_4->set_value( value = lv_value ). + ELSE. + lv_value = -cell_value. + CONDENSE lv_value. + lo_element_4->set_value( value = lv_value ). + ENDIF. + + lo_element_3->append_child( new_child = lo_element_4 ). " value node + ENDIF. + + lo_element_2->append_child( new_child = lo_element_3 ). " column node + + ADD 1 TO lv_cell_tabix. + READ TABLE io_worksheet->sheet_content ASSIGNING INDEX lv_cell_tabix. +* sy-subrc <> 0 always corresponds to the end of the last while loop + ENDWHILE. ENDIF. - lo_element_2->append_child( new_child = lo_element_3 ). " column node - ls_last_row = . - ENDLOOP. - IF sy-subrc = 0. - " Row visibility of previos row. - IF lo_row->get_visible( ) = abap_false OR - ( lo_autofilter IS BOUND AND - lo_autofilter->is_row_hidden( ls_last_row-cell_row ) = abap_true ). - lo_element_2->set_attribute_ns( name = 'hidden' value = 'true' ). - ENDIF. rv_ixml_sheet_data_root->append_child( new_child = lo_element_2 ). " row node - ENDIF. - DELETE io_worksheet->sheet_content WHERE cell_value = lc_dummy_cell_content. "#EC CI_SORTSEQ " Get rid of dummyentries + ENDLOOP. + ENDMETHOD.