*&---------------------------------------------------------------------*
*& Report  Z_SHOW_PCA_TABLES                                           *
*&---------------------------------------------------------------------*
*& This program shows the PCA tables (PCA = Post Copy Automation).     *
*& The PCA tool handles tables to be considered (backed up / restored) *
*& in the scope of a system refresh.                                   *
*& You need SAP_BASIS >= 740 for running this program (or you need to  *
*& replace some ABAP language elements with older / obsolete ones).    *
*& It is based on SAP standard program SCTC_LIST_TABLES and enriched   *
*& with the possibility to generate XML files for the Sc4SAP command   *
*& line tool for doing pre- and post-work in the context of a system   *
*& refresh.                                                            *
*&                                                                     *
*& There are some tables that are not to be processed with             *
*& all their complete data in the context of a system refresh:         *
*&   DOKIL                                                             *
*&       For component LOGINSCREEN only the entries of tables          *
*&       tables DOKIL, DOKHL and DOKTL with                            *
*&         ID = 'TX'                                                   *
*&         OBJECT = 'ZLOGIN_SCREEN_INFO'                               *
*&       are relevant. R3trans rejects the normal way with             *
*&         SELECT * FROM DOKIL WHERE ...                               *
*&       with message 'DOKHL must be exported as object 'DOCU'.'       *
*&       Only way is 'select docu TXZLOGIN_SCREEN_INFO'.               *
*&   NRIV                                                              *
*&       For component SWU3 or SWU3_DATA only these entries are        *
*&       relevant:                                                     *
*&         OBJECT = 'SWE_EVTID', 'SWW_WIID'                            *
*&       For component SAP_OFFICE:                                     *
*&         OBJECT = 'SO_OBJ_USR', 'SO_OBJ_ADR', 'SO_OBJ_FOL',          *
*&                  'SO_OBJ_DLI'                                       *
*&       For component OFFICE_ATT:                                     *
*&         OBJECT = 'SO_OBJ_RAW'                                       *
*&   TADIR                                                             *
*&       For component ALECUST only these entries are relevant:        *
*&         PGMID = 'R3TR' and OBJECT = 'IDOC'                          *
*&       For component TMS:                                            *
*&         PGMID = 'HEAD' and OBJECT = 'SYST'                          *
*&       For component SMW0:                                           *
*&         PGMID = 'R3TR' and OBJECT = 'W3HT'                          *
*& For these tables a WHERE condition is specified.                    *
*&                                                                     *
*& Some components are to handled with the 'PCA classic' procedure:    *
*&   means, that a transport request is not to be used for export /    *
*&   import, and therefore no parallelism of R3trans can be achieved   *
*&   at import.                                                        *
*&   TC_TASKRUN, TC_TASKVARI, OFFICE_ATT, SNRO, ALECUST, TMS, SMW0     *
*&   are explicitely to be handled with classic mode according to      *
*&   function module SCTC_REFRESH_GET_PCA_MODE.                        *
*&   If there are components where not all tables could be put into a  *
*&   transport request. This will be denied from the transport system  *
*&   some specific tables. Also for these components the 'PCA classic' *
*&   procedure is to be used, which will disable the parallel option   *
*&   for R3trans.                                                      *
*&---------------------------------------------------------------------*
*& Creation: 01.06.2023  Shortcut IT GmbH                              *
*&           03.08.2023  Added info about client dependency and button *
*&                       for showing DDic information.                 *
*&           15.08.2024  Added pre- and postprocessing for component   *
*&                       USER (shadow tables with address pointer)     *
*&           23.08.2024  Added run time optimization:                  *
*&                       - option for avoiding multiple export/import  *
*&                         of tables that are part of multiple         *
*&                         components                                  *
*&                       - option for creating multiple XML files for  *
*&                         using parallelization                       *
*&           19.09.2024  Added further run time optimization:          *
*&                       - using command files for R3trans (enables    *
*&                         parallel = ... in R3trans)                  *
*&                       - splitting components into pieces in case    *
*&                         their size is significantly bigger than the *
*&                         average of a task's size (optional)         *
*&           04.10.2024  Naming of XML file for 'Backup' purpose       *
*&                         without '...Export'                         *
*&           30.01.2025  Switching components to PCA classic mode in   *
*&                         case at least one table can not be put into *
*&                         a transport request.                        *
*&           12.02.2025  Use INT8 field for sum calculation of sizes   *
*&           13.02.2025  Added splitting possibility for component     *
*&                         USER (2 additional XML files!), added push  *
*&                         buttons for additional information.         *
*&           03.03.2025  Use Floating point type for sum calculation   *
*&                         of sizes (INT8 needs >=750).                *
*&           10.03.2025  Added information about total amount of com-  *
*&                         ponents and tables in ALV header.           *
*&           28.04.2025  Added option for temporary extension of max   *
*&                         wp runtime (and set it to default afterw.)  *
*&           05.05.2025  Corrected size and row information for tables *
*&                         processed partly (NRIV, TADIR, DOKIL).      *
*&           13.05.2025  In case of using parallel tasks check the     *
*&                         setting in SCC4 (T000-CCCORACTIV should not *
*&                         be set to 3 (=no transports allowed)).      *
*&           11.06.2025  Some optimization related to ALV filter and   *
*&                         cancelation of file selection dialog for    *
*&                         storing XML files.                          *
*&           04.08.2025  Putting field names in WHERE clause in double *
*&                         quotes (for avoiding strange error with     *
*&                         R3trans in S/4HANA system).                 *
*&           14.08.2025  Found that the SPTH* tables are not considered*
*&                         in the PCA tool. Added option for adding    *
*&                         them for processing.                        *
*&---------------------------------------------------------------------*
program Z_SHOW_PCA_TABLES.
include sctc_sc_incl_components.
" List tables relevant for... Refresh | Data Cleanup
selection-screen begin of block 1 with frame title ltxt1.
selection-screen begin of line.
  selection-screen comment (60) txt_r for field refresh.
  parameters: refresh type c radiobutton group r1 user-command PB1.
selection-screen end of line.
selection-screen begin of line.
  selection-screen comment (60) txt_t for field truncate.
  parameters: truncate type c radiobutton group r1.
selection-screen end of line.
selection-screen begin of line.
  selection-screen comment (60) txt_s for field pNRIV.
  parameters: pnriv type c as checkbox.
  selection-screen pushbutton 70(4) nrivBtn user-command NRI.
selection-screen end of line.
selection-screen begin of block 2 with frame title ltxt_mc.
selection-screen begin of line.
  selection-screen comment (60) txt_sp for field pS_PATH.
  parameters: pS_PATH type c as checkbox.
  selection-screen pushbutton 68(4) mCmp1Btn user-command MC1.
selection-screen end of line.
selection-screen end of block 2.
selection-screen end of block 1.
" Data for XML file generation
selection-screen begin of block 3 with frame title ltxt2.
selection-screen begin of line.  " Backup"
  selection-screen comment (60) txt_1 for field pbackup.
  parameters: pBackup type c radiobutton group r2 user-command PB2.
selection-screen end of line.
selection-screen begin of line.  " System refresh
  selection-screen comment (60) txt_2 for field psysref.
  parameters: pSysref type c radiobutton group r2.
selection-screen end of line.
selection-screen begin of line.  " Connection
  selection-screen comment (60) txt_c for field pConn.
  parameters: pConn type char120 obligatory lower case
              default '+++ Enter the connection here +++'.
selection-screen end of line.
selection-screen begin of line.  " Path for R3trans files
  selection-screen comment (60) txt_d for field ppath.
  parameters: ppath type char120 obligatory lower case
              default '$dir_home$systemrefresh'.
selection-screen end of line.
selection-screen begin of line.  " Avoid multiple export/import
  selection-screen comment (60) txt_m for field pRedund.
  parameters: pRedund type c as checkbox.
  selection-screen pushbutton 70(4) redBtn user-command RED.
selection-screen end of line.
selection-screen begin of line.  " Number of parallel tasks (WP)
  selection-screen comment (60) txt_p for field pTasks.
  parameters: pTasks type numc2 obligatory default '1'.
  selection-screen pushbutton 70(4) tsksBtn user-command TSKS.
selection-screen end of line.
selection-screen begin of line.  " Split big components
  selection-screen comment (60) txt_b for field pBCsplit.
  parameters: pBCsplit type c as checkbox user-command BCSP.
  selection-screen pushbutton 70(4) bcSpBtn user-command BSI.
selection-screen end of line.
selection-screen begin of line.  " Split USER component
  selection-screen comment (60) txt_u for field pUSsplit.
  parameters: pUSsplit type c as checkbox.
  selection-screen pushbutton 70(4) usSpBtn user-command USI.
selection-screen end of line.
selection-screen begin of line.  " Number of parallel tasks (R3trans)
  selection-screen comment (60) txt_3 for field pR3Tasks.
  parameters: pR3Tasks type numc2 obligatory default '1'.
  selection-screen pushbutton 70(4) r3pBtn user-command R3P.
selection-screen end of line.
selection-screen begin of line.  " Set Max. WP Runtime
  selection-screen comment (60) txt_w for field pWPRT.
  parameters: pWPRT type c as checkbox user-command WPRT.
  selection-screen pushbutton 70(4) wprtBtn user-command WPR.
selection-screen end of line.
selection-screen begin of line.  "   3 hours
  selection-screen comment (60) txt_h for field pW3H.
  parameters: pW3H radiobutton group WP1.
selection-screen end of line.
selection-screen begin of line.  "   unlimited
  selection-screen comment (60) txt_l for field pWUNL.
  parameters: pWUNL radiobutton group WP1.
selection-screen end of line.
selection-screen end of block 3.

class zcl_InfoPopup definition.
  public section.
    types: StringTable type standard table of string with empty key.
    class-methods:
      show
        importing iTitle type string
                  iHeader type string
                  iLines type StringTable optional,
      addLine
        importing iLine type string,
      preferPopupWithTable,
      preferPopupDisplayStrings,
      init.
  private section.
    class-data:
      infoLines type StringTable,
      prefer type c value 'W',  " Default: use POPUP_WITH_TABLE
      fmPopupDisStringsExists type abap_bool,
      fmPopupDisStringsChecked type abap_bool.
endclass.
class zcl_InfoPopup implementation.
  method preferPopupWithTable.
    prefer = 'W'.
  endmethod.
  method preferPopupDisplayStrings.
    prefer = 'D'.
  endmethod.
  method show.
    if iLines is supplied.
      infoLines[] = iLines[].
    endif.
    if fmPopupDisStringsChecked = abap_false.
      call function 'FUNCTION_EXISTS'
          exporting funcname = 'POPUP_DISPLAY_STRINGS'
          exceptions function_not_exist = 1.
      if sy-subrc = 0.
        fmPopupDisStringsExists = abap_true.
      endif.
      fmPopupDisStringsChecked = abap_true.
    endif.
    if fmPopupDisStringsExists = abap_true and prefer = 'D'.
      data: lines type VMCDBG_STRING_TABLE.
      lines[] = infoLines[].
      call function 'POPUP_DISPLAY_STRINGS'
          exporting
            P_TAB           = lines
            P_TITLE         = iTitle
            P_COLUMN_HEADER = iHeader.
    else.
      call function 'POPUP_WITH_TABLE'   ##FM_SUBRC_OK
          exporting
            endpos_col = 80
            endpos_row = 10 + lines( infoLines )
            startpos_col = 10
            startpos_row = 10
            titletext = iHeader
          tables
            valuetab = infoLines
          exceptions           " Don't care about ending of the popup
            break_off = 1
            others    = 2.
    endif.
  endmethod.
  method addLine.
    insert iLine into table infoLines.
  endmethod.
  method init.
    clear infoLines.
    prefer = 'W'.
  endmethod.
endclass.
class EventHandler definition deferred.
" An exception for PCATablesALV
class zcl_exc_PCATables definition inheriting from CX_STATIC_CHECK.
  public section.
    data text type string read-only.
    methods constructor importing text type string.
endclass.
class zcl_exc_PCATables implementation.
  method constructor.
    super->constructor( ).
    me->text = text.
  endmethod.
endclass.

* A derivation of an ALV Grid
class PCATablesALV definition inheriting from cl_gui_alv_grid.
  public section.
    types: begin of TAlvLine,
             component     type ECH_DTE_COMPONENT,
             tabname       type tabname,
             tabClass      type tabclass,
             sizeKb        type int4,
             rows          type int4,
             tableDescr    type ddtext,
             clntDependent type icon_d,
             infoButton    type icon_d,
             tableStatus   type ddgotstate,
             linecolor     type char4,
             warning       type abap_bool,
             added         type abap_bool,
           end of TAlvLine.
    types: AlvLines type standard table of TAlvLine
               with non-unique key component tabname.
    types: StringTable type standard table of string with default key.
    data:  fieldCatalog       type LVC_T_FCAT,
           alvDatatab         type AlvLines,
           totalComponents    type i read-only,
           totalTables        type i read-only.
    methods:
      getData
        raising zcl_exc_PCATables,
      setPurpose
        importing iPurpose type char20,
      setConnection
        importing iConnection type char120,
      setPath4R3transFiles
        importing iPath type char120,
      setAvoidRedundantExportImport
        importing iValue type abap_bool,
      setParallelTasks
        importing iValue type numc2,
      setParallelR3Tasks
        importing iValue type numc2,
      setSplitBigComponents
        importing iValue type abap_bool,
      setWithoutNRIVSNRO
        importing iValue type abap_bool,
      setAddSPATH
        importing iValue type c,
      setRefreshOrTruncate
        importing iValue type c,
      generateXMLFiles,
      handleChangedFilter,
      showDDicInfo
        importing iRow type int4.
  private section.
    constants: FACTOR4SPLITTING type f value '1.2'.
    types: begin of ComponentAndTable,
             component type ECH_DTE_COMPONENT,
             table type tabname,
           end of ComponentAndTable,
           ComponentsAndTables type standard table of ComponentAndTable
               with default key,
           begin of ExcludedTable,
             table  type tabname,
             reason type string,
           end of ExcludedTable,
           begin of TaskComponent,
             task type i,
             component type ECH_DTE_COMPONENT,
             partNo type i,
             tables type standard table of tabname with default key,
             kbSize type f,
           end of TaskComponent,
           begin of TaskSpace,
             task type i,
             kbSize type f,
             components type i,
           end of TaskSpace,
           begin of ComponentSpace,
             component type ECH_DTE_COMPONENT,
             tables type standard table of tabname with default key,
             kbSize type f,
           end of ComponentSpace,
           begin of TableSpace,
             table type tabname,
             kbSize type f,
           end of TableSpace,
           begin of TableAndWhereCondition,
             table type tabname,
             whereCond type string,
             r3transCmd type string,
           end of TableAndWhereCondition,
           TablesAndWhereConditions type standard table of TableAndWhereCondition
               with default key,
           begin of TableAlias,
             component type ECH_DTE_COMPONENT,
             alias type tabname,
             tablenames type standard table of tabname with default key,
           end of TableAlias,
           begin of CompAndTableWithFlag,
             component type ECH_DTE_COMPONENT,
             table type tabname,
             flag type abap_bool,
           end of CompAndTableWithFlag,
           begin of OwnSortOrder,
             no type i,
             alvLine type TALVLine,
           end of OwnSortOrder,
           begin of PCAClassicCheck,
             tabname type tabname,
             checked type abap_bool,
             useClassicMode type abap_bool,
           end of PCAClassicCheck,
           TasksComponents type standard table of TaskComponent
               with key component partNo,
           TasksSpace type standard table of TaskSpace
               with key task,
           SpacePerComponent type standard table of ComponentSpace
               with key component,
           SpacePerTable type standard table of TableSpace
               with key table.
    data: action type sctc_sc_dte_action,
          tables2BeExcluded type sorted table of ExcludedTable
              with unique key table,
          components4ClassicMode type sorted table of ECH_DTE_COMPONENT
              with unique default key,
          pcaClassicChecks type sorted table of PCAClassicCheck
               with unique key tabname,
          componentsNot2BeSplitted type sorted table of ECH_DTE_COMPONENT
              with unique default key,
          exclTables type sorted table of ExcludedTable
              with unique key table,
          tablesWithWhereCondition type ComponentsAndTables,
          tables4WarningWithFullContent type standard table of tabname,
          tables4Warning type ComponentsAndTables,
          tableAliases type standard table of TableAlias with default key,
          tablesAlreadyProcessed type sorted table of tabname
              with unique default key,
          tablesPossiblyMissedInPCA type ComponentsAndTables,
          tasksWithComponents type TasksComponents,
          tasksWithSpace type TasksSpace,
          componentsWithSpaces type SpacePerComponent,
          alvSelectedDatatab type AlvLines,
          xmlFileLines       type standard table of string,
          purpose            type string,
          exportImportRemove type string.
    data: txtClntDependent type char4,
          txtClntIndependent type char4,
          txtDDicInfo type char4.
    data: eventHandler type ref to EventHandler,
          selectedRows type lvc_t_row,
          filteredRows type lvc_t_fidx,
          xmlFilename  type string,
          xmlFileAbsPath type string,
          refreshOrTruncate type c,
          path4R3transFiles type string,
          pathSeparator type string,
          connection type string,
          withoutNRIVSNRO type abap_bool,
          addSPATH type abap_bool,
          avoidRedundantExportImport type abap_bool,
          splitBigComponents type abap_bool,
          kbTotal type f,
          beforeUserExportDone type abap_bool,
          afterUserImportDone type abap_bool,
          allDownloadsDone type abap_bool,
          parallelTasks type i,
          parallelR3Tasks type i.
    methods:
      createFieldCatalog,
      addToFieldCatalog
        importing iFieldname type slis_fieldname
                  iFieldText type SCRTEXT_M
                  iOutputLen type i optional,
      addToExcludedTables
        importing iTable type tabname
                  iReason type string,
      getDataFromPCATool,
      addTable2ALV
        importing iComponent type string
                  iTableName type tabname
                  iWarning   type abap_bool optional
                  iAdded     type abap_bool optional
        returning value(added) type abap_bool,
      colorTheLines,
      isToBeShownWithWarning
        importing iComponent type string
                  iTableName type tabname
        returning value(result) type abap_bool,
      getSelectedALVData
        exporting eNumberOfComponents type i
        returning value(result) type AlvLines,
      getClientDependency
        importing iTableName type tabname
        returning value(eClntDependent) type abap_bool,
      getSizeAndRowCount
        importing iComponent type string
                  iTableName type tabname
        exporting eSizeKB type i
                  eRowCount type i,
      getSizeAndRows4SpecialTable
        importing iComponent type string
                  iTableName type tabname
        exporting eSizeKB type i
                  eRowCount type i,
      genXMLFiles,
      genSingleXMLFile4Purpose
        returning value(done) type abap_bool,
      genXMLFileHeader
        importing iTask type i,
      getComponentsWithSpaces,
      genLinesForComponent
        importing iTaskComponent type TaskComponent,
      getXML4MaxWPRuntimeExtend
        returning value(result) type StringTable,
      getXML4MaxWPRuntimeDefault
        returning value(result) type StringTable,
      getWhereCondition4SpecialTable
        importing iCompAndTable type ComponentAndTable
                  i4SelOrR3trans type c
        changing cTablesAndWhereConds type ref to TablesAndWhereConditions,
      getWhereCond4NRIV
        importing iComponent type ECH_DTE_COMPONENT
                  iQMark type c
        changing cTablesAndWhereConds type ref to TablesAndWhereConditions,
      getWhereCond4TADIR
        importing iComponent type ECH_DTE_COMPONENT
                  iQMark type c
        changing cTablesAndWhereConds type ref to TablesAndWhereConditions,
      getWhereCond4DOKIL
        importing iComponent type ECH_DTE_COMPONENT
                  iQMark type c
        changing cTablesAndWhereConds type ref to TablesAndWhereConditions,
      eliminateDuplicateTables
        changing cCompsAndTables type ALVLines,
      pushBackCompsCvrdInOtherComps
        changing cCompsAndTables type ALVLines,
      genCallBeforeExpAddress3
        importing iTaskComponent type TaskComponent,
      genCallAfterImpAddress3
        importing iTaskComponent type TaskComponent,
      getXML4BeforeUserExport
        returning value(result) type StringTable,
      getXML4AfterUserImport
        returning value(result) type StringTable,
      createXML4BeforeUserExport,
      createXML4AfterUserImport,
      createXML4WPRuntimeExtend,
      createXML4WPRuntimeDefault,
      specifySpecialTables,
      specifyTables4Warning,
      specifyComponents4ClassicMode
        raising zcl_exc_PCATables,
      checkTablesOfComp4ToC
        raising zcl_exc_PCATables,
      isTableUsableInToC
        importing iTrKorr type trkorr
                  iTableName type tabname
        returning value(result) type abap_bool,
      specifyComponentsNot2Split,
      addTableWithWhereCondition
        importing iComponent type ECH_DTE_COMPONENT
                  iTableName type tabname,
      addTableAlias
        importing iComponent type ECH_DTE_COMPONENT
                  iAlias     type tabname
                  iTableName type tabname,
      specifyTablesPossMissed,
      addTable4Warning
        importing iComponent type ECH_DTE_COMPONENT
                  iTableName type tabname,
      addTabPossiblyMissed
        importing iComponent type ECH_DTE_COMPONENT
                  iTableName type tabname,
      ask4DownloadPath
        raising zcl_exc_PCATables,
      beforeExportOfComponent
        importing iTaskComponent type TaskComponent,
      afterImportOfComponent
        importing iTaskComponent type TaskComponent,
      divideComponentsIntoTasks,
      splitComponent
        importing iTotalKbSize type f
                  iComponentSpace type ComponentSpace,
      assignComponents2Tasks
        importing iTotalKbSize type f,
      tablesOfComponentAsString
        importing iTaskComponent type TaskComponent
                  iNotWithWhereCond type abap_bool
        changing cWhereCondsOfComponent type TablesAndWhereConditions optional
                 cCntTables type i optional
                 cCntWhere type i optional
        returning value(result) type string,
      getCommentLine4Task
        importing iTaskComponent type TaskComponent
        returning value(result) type string,
      addWhereConditions2Xml
        importing iTablesAndWhereConds type TablesAndWhereConditions,
      determineSAPPathSeparator,
      useDelBeforeImport
        importing iComponent type ECH_DTE_COMPONENT
        returning value(result) type abap_bool,
      useCommandFile
        importing iComponent type ECH_DTE_COMPONENT
                  iTablesTotal type i
                  iTablesWithWhereCond type i
        returning value(result) type abap_bool,
      addComponent2Task
        importing iTaskComponent type TaskComponent,
      addXmlLine
        importing iLine type string,
      isInSelection
        importing iIndex type i
        returning value(result) type boolean,
      isConfirmedAfterWarning
        importing iCompAndTable type ComponentAndTable
        returning value(result) type boolean,
      downloadXMLFile4Task
        importing iTask type i
        returning value(done) type boolean
        raising zcl_exc_PCATables,
      downloadXMLFile
        importing iFilename type string
        returning value(done) type boolean,
      showProgressInfo
        importing iText type string
                  iMaxCnt type i optional
                  iCurrentCnt type i optional,
      infoPopupAfterXMLGeneration.
endclass.

class PCATablesALV implementation.
  " Supply some information what's currently going on.
  method showProgressInfo.
    data: percentage type i.
    if ( iMaxCnt > 0 ).
      percentage = iCurrentCnt * 100 / iMaxCnt.
    endif.
    call function 'SAPGUI_PROGRESS_INDICATOR'
         exporting percentage = percentage
                   text = iText.
  endmethod.
  " Get the data to be shown.
  method getData.
    case refreshOrTruncate.
      when 'R'.
        action = cv_refresh.
      when 'T'.
        action = cv_truncate.
      when others.
        data(e) = new zcl_exc_PCATables( 'Specification for <REFRESH> | <TRUNCATE> missing.' ).
        raise exception e.
    endcase.
    " Empty some tables possibly containing information that is
    "   to be renewed.
    clear: components4ClassicMode, componentsWithSpaces,
           componentsNot2BeSplitted, kbTotal,
           tablesWithWhereCondition, tables4Warning, tables4WarningWithFullContent.
    if me->gui_is_running is initial.
      txtClntDependent = 'yes'.
      txtClntIndependent = 'no'.
    else.
      txtClntDependent = ICON_OKAY.
      txtClntIndependent = ICON_CANCEL.
      txtDDicInfo = ICON_INFORMATION.
    endif.
    createFieldCatalog( ).
    specifySpecialTables( ).
    specifyTables4Warning( ).
    specifyTablesPossMissed( ).
    getDataFromPCATool( ).
  endmethod.

  method getDataFromPCATool.
    data: component type string,
          prevComponent type string,
          components type stringtab,
          allComponents type stringtab,
          tabname type tabname,
          tables type SCTC_SC_T_TABNAME,
          msgHandler type ref to if_sctc_msg_handler,
          bapiReturn type bapirettab,
          tableAdded type abap_bool,
          warning type abap_bool,
          exc type ref to cx_sctc_fatal_error.
    clear: tables2BeExcluded, alvDatatab, totalComponents, totalTables.
    showProgressInfo( iText = 'Get components and tables...' ).
    " Function module SCTC... needs a log
    msgHandler = cl_sctc_fac_msg_handler=>get_msg_handler( ).
    TRY.
        msgHandler->create_log(
            iv_ext_lognr     = 'SCTC_LIST_TABLES'
            iv_log_subobject = 'BACKEND' ).
      CATCH cx_sctc_fatal_error INTO exc.
        MESSAGE exc TYPE 'E'.
    ENDTRY.
    " Get the components
    CALL FUNCTION 'SCTC_GET_ALL_COMPONENTS'
      IMPORTING
        et_components = allComponents.
    sort allComponents.
    delete adjacent duplicates from allComponents comparing all fields.
    loop at allComponents into component.
      if not ( withoutNRIVSNRO = abap_true and
             ( component = 'SNRO' or
               component = 'NRIV' ) ).
        insert component into table components.
      endif.
    endloop.
    " Get the tables for each component
    loop at components into component.
      showProgressInfo(
          exporting iText = |Get tables of component { component } |
                    iMaxCnt = lines( components )
                    iCurrentCnt = sy-tabix ).
      clear tables.
      CALL FUNCTION 'SCTC_GET_WHITELIST'
        EXPORTING
          i_component_name  = component
          i_action          = action
          io_msg_handler    = msgHandler
          iv_flg_check_auth = '-'
        IMPORTING
          e_whitelist       = tables.
      loop at tables into tabname.
        warning = isToBeShownWithWarning( iComponent = component iTableName = tabname ).
        addTable2ALV( iComponent = component
                      iTableName = tabname
                      iWarning   = warning ).
      endloop.
    endloop.
    " Now check if some tables are missing / not considered in PCA tool.
    loop at tablesPossiblyMissedInPCA reference into data(m).
      if not line_exists( alvDataTab[ tabname = m->table ] ).
        component = m->component.
        if prevComponent <> component.
          prevComponent = component.
          showProgressInfo(
              exporting iText = |Add tables of component { component }|
                        iMaxCnt = 1 iCurrentCnt = 1 ).
        endif.
        tableAdded = addTable2ALV( iComponent = component
                                   iTableName = m->table
                                   iAdded     = abap_true ).
      endif.
    endloop.
    " Show only active tables
    delete alvDataTab where tableStatus <> 'A'.
    totalTables = lines( alvDataTab ).
    loop at alvDataTab reference into data(r).
      at new component.
        add 1 to totalComponents.
      endat.
    endloop.
    colorTheLines( ).
    " Display Error Messages
    bapiReturn[] = msgHandler->get_bapirettab( ).
    IF bapiReturn IS NOT INITIAL.
      msgHandler->save_log( ).
    ENDIF.
    sort alvDataTab by component tabname.
    showProgressInfo( iText = '...done' ).
  endmethod.

  method addTable2ALV.
    data: newLine type TAlvLine,
          clntDependent type abap_bool,
          tableInfo type dd02v.
    added = abap_false.
    " Data for current table already known?
    read table alvDataTab into newLine
        with key tabname = iTableName.
    newLine-component = iComponent.
    " Table appears the 1st time: get some information.
    if sy-tabix = 0.
      newLine-tabName = iTableName.
      " Get short description of the table.
      CALL FUNCTION 'DDIF_TABL_GET'
        EXPORTING
          name          = iTablename
          langu         = sy-langu
        IMPORTING
          dd02v_wa      = tableInfo
          gotstate      = newLine-tableStatus
        EXCEPTIONS
          illegal_input = 1
          OTHERS        = 2.
      IF sy-subrc <> 0.
        MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
                  WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      ENDIF.
      IF newLine-tableStatus = 'A'.
        newLine-tabClass = tableInfo-tabclass.
        newLine-tableDescr = tableInfo-ddtext.
        clntDependent = getClientDependency( newLine-tabName ).
        if clntDependent = abap_true.
          newLine-clntDependent = txtClntDependent.
        else.
          newLine-clntDependent = txtClntIndependent.
        endif.
        newLine-infoButton = txtDDicInfo.
      endif.
    endif.
    if newLine-tableStatus = 'A'.
      if ( newLine-tabClass = 'TRANSP' or newLine-tabClass = 'POOL' ).
        getSizeAndRowCount(
            exporting iComponent = iComponent
                      iTableName = iTablename
            importing eSizeKB = newLine-sizeKb
                      eRowCount = newLine-rows ).
      else.
        insert value ExcludedTable(
             table = newLine-tabName reason = '(is not a table)' )
            into table tables2BeExcluded.
      endif.
      newLine-warning = iWarning.
      newLine-added   = iAdded.
      insert newLine into table alvDataTab.
      added = abap_true.
    endif.
  endmethod.

  method isToBeShownWithWarning.
    " Is it about a component + table for that a warning has to be shown (e.g. SNRO with table NRIV)
    "   or is it about a table for which a WHERE condition is to be applied (e.g. TADIR), which is undefined?
    result = abap_false.
    if ( line_exists( tables4Warning[ component = iComponent table = iTableName ] ) ) or
         ( line_exists( tables4WarningWithFullContent[ table_line = iTableName ] ) and
              not line_exists( tablesWithWhereCondition[ component = iComponent table = iTableName ] ) ).
        result = abap_true.
    endif.
  endmethod.

  " Is the table client dependent?
  method getClientDependency.
    eClntDependent = abap_false.
    data: tabFields type standard table of DFIES,
          firstField type DFIES.
    call function 'DDIF_FIELDINFO_GET'
      exporting tabname = iTableName
      tables dfies_tab = tabFields
      exceptions not_found = 1
                 internal_error = 2
                 others = 3.
    if ( sy-subrc = 0 and lines( tabFields ) > 0 ).
      read table tabFields index 1 into firstField.
      if ( firstField-domname = 'MANDT' or
           firstField-datatype = 'CLNT' ).
        eClntDependent = abap_true.
      endif.
    endif.
  endmethod.

  " Get size in KB and amount of rows for a table in a component
  method getSizeAndRowCount.
    data: alvLine type TAlvLine,
          getTableSizeRc type sy-subrc.
    clear: eSizeKB, eRowCount.
    " Only parts of the table to be processed?
    if line_exists( tablesWithWhereCondition[ component = iComponent
                                              table = iTablename ] ).
      getSizeAndRows4SpecialTable(
          exporting iComponent = iComponent
                    iTablename = iTablename
          importing eSizeKB    = eSizeKB
                    eRowCount  = eRowCount ).
    else.
      " Full table to be processed. Data for current table already known?
      read table alvDataTab into alvLine
          with key tabname = iTablename.
      if sy-subrc = 0.
        eSizeKB = alvLine-sizekb.
        eRowCount = alvLine-rows.
      else.
        " If not, get the data.
        call function 'DB_GET_TABLE_SIZE'         ##FM_SUBRC_OK
            exporting tabname  = iTablename
                      select_count = 'X'
            importing size_kb  = eSizeKB
                      rowcount = eRowCount
                      subrc    = getTableSizeRc
            exceptions WRONG_SCHEMA         = 1
                       NO_OF_POOLS_EXCEEDED = 2
                       OP_FAILURE           = 3
                       OTHERS               = 4.
      endif.
    endif.
    " DB2 is soooo slow with offering table information. For
    "   avoiding a timeout (max wp runtime is usually 3600 seconds),
    "   fire a COMMIT WORK.
    if sy-dbsys cs 'DB2' or sy-dbsys cs 'DB6'.
      commit work.
    endif.
  endmethod.

  method getSizeAndRows4SpecialTable.
    clear: eSizeKB, eRowCount.
    data: compAndTable type ComponentAndTable,
          tablenames type standard table of tabname with empty key,
          tablename type tabname,
          rowCount type i,
          whereCondsOfTable type TablesAndWhereConditions,
          singleWhereCondOfTable type TableAndWhereCondition,
          wCRef type ref to TablesAndWhereConditions,
          whereCond type string,
          tableAlias type TableAlias,
          typeDescr type ref to cl_abap_typedescr,
          rowcount_f    type f,
          table_size_f  type f,
          table_size_f_total type f.
    compAndTable-component = iComponent.
    compAndTable-table     = iTablename.
    get reference of whereCondsOfTable into wCRef.
    " Get the WHERE condition (can be multiple - to be processed with OR)
    getWhereCondition4SpecialTable(
        exporting iCompAndTable = compAndTable
                  i4SelOrR3trans = 'S'
        changing  cTablesAndWhereConds = wCRef ).
    loop at whereCondsOfTable into singleWhereCondOfTable.
      if sy-tabix = 1.
        whereCond = singleWhereCondOfTable-whereCond.
      else.
        concatenate whereCond 'OR' singleWhereCondOfTable-whereCond
            into whereCond separated by space.
      endif.
    endloop.
    read table tableAliases
        with key component = iComponent
                 alias     = iTablename
        into tableAlias.
    if sy-subrc = 0.
      tablenames = tableAlias-tablenames.
    else.
      insert iTablename into table tablenames.
    endif.
    loop at tablenames into tablename.
      " Get the record line length
      typeDescr = cl_abap_typedescr=>describe_by_name( tablename ).
      " Count the records and calculate the size in KB.
      select count(*) into rowCount from (tablename)
          client specified bypassing buffer
          where (whereCond).
      if sy-subrc = 0.
        add rowCount to eRowCount.
        table_size_f = rowcount * typeDescr->length / 1024.
        add table_size_f to table_size_f_total.
      endif.
    endloop.
    eSizeKB = table_size_f_total.
  endmethod.

  " Columns in ALV list
  method createFieldCatalog.
    addToFieldCatalog( iFieldName = 'COMPONENT'  iFieldText = 'Component' iOutputLen = 30 ).
    addToFieldCatalog( iFieldName = 'TABNAME'    iFieldText = 'Table'     iOutputLen = 40 ).
    addToFieldCatalog( iFieldName = 'TABLEDESCR' iFieldText = 'Table description' iOutputLen = 60 ).
    addToFieldCatalog( iFieldName = 'TABCLASS'   iFieldText = 'Table class' iOutputLen = 8 ).
    addToFieldCatalog( iFieldName = 'SIZEKB'     iFieldText = 'Size in KB' ).
    addToFieldCatalog( iFieldName = 'ROWS'       iFieldText = 'Rows' ).
    addToFieldCatalog( iFieldName = 'CLNTDEPENDENT' iFieldText = 'Client dependent?' ).
    if ( gui_is_running = 'X' ).
      addToFieldCatalog( iFieldname = 'INFOBUTTON'  iFieldText = 'DDic info' ).
    endif.
    " Client dependency is shown as Icon, looks better with centered alignment.
    loop at fieldcatalog reference into data(fCatLine)
        where fieldname = 'CLNTDEPENDENT'.
      fCatLine->just = 'C'.
    endloop.
    " Same for 'InfoButton', and show it as button
    loop at fieldcatalog reference into fCatLine
        where fieldname = 'INFOBUTTON'.
      fCatLine->just = 'C'.
      fCatLine->style = fCatLine->style bit-xor
                  cl_gui_alv_grid=>MC_STYLE_BUTTON bit-xor
                  cl_gui_alv_grid=>MC_STYLE_ENABLEd.
    endloop.
  endmethod.

  method addToFieldCatalog.
    data: singleField type LVC_S_FCAT.
    singleField-fieldname = iFieldname.
    singleField-scrtext_m = iFieldText.
    if iOutputLen is supplied.
      singleField-outputlen = iOutputLen.
    endif.
    append singleField to fieldcatalog.
  endmethod.

  method handleChangedFilter.
    data: alvSelTab type AlvLines,
          numComps type i,
          gridTitle type LVC_TITLE.
    alvSelTab = getSelectedAlvData( importing eNumberOfComponents = numComps ).
    " In case components and / or tables are deselected, give an information
    "   in the ALV title.
    if ( numComps <> totalComponents or lines( alvSelTab ) <> totalTables ).
      gridTitle = |PCA Tables (total: { totalComponents } components / { totalTables } tables,|.
      gridTitle = |{ gridTitle } selected: { numComps } / { lines( alvSelTab ) })|.
    else.
      gridTitle = |PCA Tables ({ totalComponents } components, { totalTables } tables)|.
    endif.
    set_gridtitle( gridTitle ).
  endmethod.

  method colorTheLines.
    loop at alvDataTab reference into data(r).
      if r->warning = abap_true.
        r->linecolor = 'C310'. " Yellow and bold
        modify alvDataTab from r->*.
      elseif r->added = abap_true.
        r->linecolor = 'C510'. " Green and bold
      endif.
    endloop.
  endmethod.

  method generateXMLFiles.
    data: compAndTable type ComponentAndTable,
          tabname type tabname,
          alvLine type TAlvLine,
          exc type ref to zcl_exc_PCATables.
    clear: xmlFileLines, filteredRows,
           exclTables, tablesAlreadyProcessed,
           xmlFileAbsPath, tasksWithComponents, tasksWithSpace.
    allDownloadsDone = abap_false.
    beforeUserExportDone = abap_false.
    afterUserImportDone = abap_false.
    alvSelectedDatatab = getSelectedALVData( ).
    determineSAPPathSeparator( ).
    " Refresh (Export/Import) for System refresh? Check whether
    "   component is to be handled with Classic PCA mode.
    if purpose = 'SystemRefresh' and refreshOrTruncate = 'R'.
      try.
        specifyComponents4ClassicMode( ).
      catch zcl_exc_PCATables into exc.
        message exc type 'E'.
      endtry.
    endif.
    specifyComponentsNot2Split( ).
    " Check if component + table is included for which a warning should be given.
    loop at tables4Warning into compAndTable.
      if ( line_exists( alvSelectedDatatab[ component = compAndTable-component tabname = compAndTable-table ] ) ).
        if ( not isConfirmedAfterWarning( compAndTable ) ).
          return.
        endif.
      endif.
    endloop.
    " Check if furthermore a table is included with its full content for which a warning should be given.
    loop at alvSelectedDatatab into data(sel).
      " Warning for this component and table already given? Next...
      if line_exists( tables4Warning[ component = sel-component table = sel-tabname ] ).
        continue.
      endif.
      " Hit for the table and no WHERE condition given for this component + table? Warning!
      if line_exists( tables4WarningWithFullContent[ table_line = sel-tabname ] ) and
          not line_exists( tablesWithWhereCondition[ component = sel-component table = sel-tabname ] ).
        compAndTable-component = sel-component.
        compAndTable-table = sel-tabname.
        if ( not isConfirmedAfterWarning( compAndTable ) ).
          return.
        endif.
      endif.
    endloop.
    " All warnings confirmed. Go!
    divideComponentsIntoTasks( ).
    cl_gui_cfw=>flush( ).
    genXMLFiles( ).
  endmethod.

  method genXMLFiles.
    allDownloadsDone = abap_true.
    case purpose.
      when 'Backup'.
        exportImportRemove = 'Export'.
        allDownloadsDone = genSingleXMLFile4Purpose( ).
      when 'SystemRefresh'.
        case action.
          when cv_refresh.
            exportImportRemove = 'Export'.
            if genSingleXMLFile4Purpose( ) = abap_true.
              clear: xmlFileLines, tablesAlreadyProcessed.
              exportImportRemove = 'Import'.
              genSingleXMLFile4Purpose( ).
            else.
              allDownloadsDone = abap_false.
            endif.
          when cv_truncate.
            exportImportRemove = 'Remove'.
            allDownloadsDone = genSingleXMLFile4Purpose( ).
        endcase.
    endcase.
    if ( allDownloadsDone = abap_true ) and ( not pWPRt is initial ).
      createXML4WPRuntimeExtend( ).
      createXML4WPRuntimeDefault( ).
    endif.
    if ( allDownloadsDone = abap_true ).
      infoPopupAfterXMLGeneration( ).
      message |Files created successfully| type 'S'.
    endif.
  endmethod.

  method genSingleXMLFile4Purpose.
    data: taskComponent type TaskComponent,
          thisDownloadDone type abap_bool.
    done = abap_false.
    genXMLFileHeader( 1 ).
    loop at tasksWithComponents reference into data(tC).
      at new task.
        clear: xmlFileLines.
        genXMLFileHeader( tC->task ).
      endat.
      genLinesForComponent( tC->* ).
      at end of task.
        if ( pWPRT = abap_true and parallelTasks = 1 ).
          insert lines of getXML4MaxWPRuntimeDefault( ) into table xmlFileLines.
        endif.
        addXmlLine( '</ExecutionChain>' ).
        try.
          thisDownloadDone = downloadXMLFile4Task( iTask = tC->Task ).
          if ( thisDownloadDone = abap_false ).
            allDownloadsDone = abap_false.
            return.
          endif.
        catch zcl_exc_PCATables into data(exc2).
          message exc2->text type 'I'.
          return.
        endtry.
      endat.
    endloop.
    done = abap_true.
  endmethod.

  method genLinesForComponent.
    data: tabsOfComp type standard table of tablename,
          table      type tabname,
          tables     type string,
          taskComp   type TaskComponent,
          whereCondsOfComponent type TablesAndWhereConditions,
          tAndWs type ref to TablesAndWhereConditions,
          tableAndWhereCond type TableAndWhereCondition,
          rowIndex   type lvc_index,
          useDelBeforeImport type abap_bool,
          useCommandFile type abap_bool,
          commentLine type string,
          cntTables  type i,
          cntWhere   type i.
    " Get all tables of the component in a comma separated string,
    "   the total amount of tables and the amount of tables with Where condition.
    tables = tablesOfComponentAsString(
                 exporting iTaskComponent = iTaskComponent
                           iNotWithWhereCond = abap_false
                 changing cWhereCondsOfComponent = whereCondsOfComponent
                          cCntTables = cntTables
                          cCntWhere = cntWhere ).
    " No tables and it's not about import of a data file? => nothing to do.
    if ( tables is initial and exportImportRemove <> 'Import' ).
      return.
    endif.
    useCommandFile = useCommandFile(
                         iComponent = iTaskComponent-component
                         iTablesTotal = cntTables
                         iTablesWithWhereCond = cntWhere ).
    " Using a command file (= transport of copies) automatically causes
    "   the deletion of records not supplied in the data file.
    " If no command file is used, we have - in the context of a system refresh -
    "   to delete the data before importing it.
    if ( useCommandFile = abap_true ).
      useDelBeforeImport = abap_false.
    else.
      useDelBeforeImport = useDelBeforeImport( iTaskComponent-component ).
    endif.
    data filePrefix type string.
    filePrefix = |{ path4R3transFiles }{ iTaskComponent-component }|.
    if ( iTaskComponent-partNo > 0 ).
      filePrefix = |{ filePrefix }_part_{ iTaskComponent-partNo }|.
    endif.
    beforeExportOfComponent( iTaskComponent ).
    if ( exportImportRemove = 'Import' ).
      " For Import the tables are not needed anymore. Take what's in the data file.
      clear tables.
    endif.
    addXmlLine( '    <Task>' ).
    addXmlLine( '        <R3trans StopOnError="true">' ).
    commentLine = getCommentLine4Task( itaskcomponent ).
    addXmlLine( |            <Comment>{ commentLine }| ).
    addXmlLine( |            <{ exportImportRemove }>| ).
    if not tables is initial.
      addXmlLine( |                <Table>{ tables }</Table>| ).
    endif.
    addXmlLine( '                <Client>*</Client>' ).
    if ( exportImportRemove = 'Remove' ).
      addXmlLine( |                <ServerLogFile>{ filePrefix }.r3trans.remove.log</ServerLogFile>| ).
    else.
      addXmlLine( |                <ServerFile>{ filePrefix }.r3trans.bin</ServerFile>| ).
    endif.
    addXmlLine( |                <UmodeIgnore>true</UmodeIgnore>| ).
    if (  exportImportRemove = 'Export' ).
      if ( useDelBeforeImport = abap_true ).
        addXmlLine( |                <DeleteBeforeImport>true</DeleteBeforeImport>| ).
      endif.
      if ( useCommandFile = abap_true ).
        addXmlLine( |                <UseCommandFile>true</UseCommandFile>| ).
      endif.
    endif.
    if ( exportImportRemove = 'Import' and parallelR3Tasks > 1 and
         not line_exists( components4ClassicMode[ table_line = iTaskComponent-component ] ) ).
      addXmlLine( |                <ParallelTasks>{ parallelR3Tasks }</ParallelTasks>| ).
    endif.
    if ( exportImportRemove = 'Export' ).
      addWhereConditions2Xml( whereCondsOfComponent ).
    endif.
    addXmlLine( |            </{ exportImportRemove }>| ).
    addXmlLine( '        </R3trans>' ).
    addXmlLine( '    </Task>' ).
    afterImportOfComponent( iTaskComponent ).
  endmethod.

  method genXMLFileHeader.
    data: alvLine type TAlvLine,
          xmlLine type string.
    addXmlLine('<ExecutionChain>').
    if ( parallelTasks = 1 ).
      addXmlLine( |    <Comment>Generated XML file for { purpose } - { exportImportRemove }</Comment>| ).
    else.
      addXmlLine( |    <Comment>Generated XML file for { purpose } - { exportImportRemove } - task { iTask }</Comment>| ).
    endif.
    xmlLine = |    <DefaultConnection>{ connection }</DefaultConnection>|.
    addXmlLine( xmlLine ).
    addXmlLine( |    <Resumption>true</Resumption>| ).
    if ( pWPRT = abap_true and parallelTasks = 1 ).
      insert lines of getXML4MaxWPRuntimeExtend( ) into table xmlFileLines.
    endif.
  endmethod.

  method beforeExportOfComponent.
    if exportImportRemove = 'Export'.
      case iTaskComponent-component.
        when 'USER'.
          genCallBeforeExpAddress3( iTaskComponent ).
      endcase.
    endif.
  endmethod.

  method afterImportOfComponent.
    if exportImportRemove = 'Import'.
      case iTaskComponent-component.
        when 'USER'.
          genCallAfterImpAddress3( iTaskComponent ).
      endcase.
    endif.
  endmethod.

  method useDelBeforeImport.
    " Use <DeleteBeforeImport> only for components using classic mode,
    "   when no command file is used.
    " And when creating the XML files for a backup, do not use it in
    "   any case. If it comes to the need to restore the data, it's on
    "   the admin to decide, whether in front of the import the data
    "   is to be deleted.
    if purpose = 'Backup'.
      result = abap_false.
      return.
    endif.
    " For Systemrefresh:
    "   For components using the classic mode (where no parallel=... is used),
    "   use <DeleteBeforeImport> in any case.
    "   For components with new PCA mode (where parallel=... is used) a command
    "   file is used, which at import causes the deletion of records not supplied
    "   in the data file.
    if line_exists( components4ClassicMode[ table_line = iComponent ] ).
      result = abap_true.
    else.
      result = abap_false..
    endif.
  endmethod.

  method useCommandFile.
    result = abap_false.
    " We use a command file for exporting components using new PCA mode.
    "   Like PCA tool we do not use it for components using classic mode.
    "   And tables with Where condition can not be managed via command file,
    "   so there are to be some tables in the component without Where condition.
    "   When a command file is used at Export, the information is written into
    "   the R3trans data file, so the Import is also working with it.
    if exportImportRemove = 'Export' and
        not ( line_exists( components4ClassicMode[ table_line = iComponent ] ) ) and
        ( iTablesTotal > iTablesWithWhereCond ).
      result = abap_true.
    endif.
  endmethod.

  method divideComponentsIntoTasks.
    data: cLine type ref to TAlvLine.
    getComponentsWithSpaces(  ).
    " Distribute the components to the tasks, from biggest to smallest.
    "   1.: create a table with a record for each task
    do parallelTasks times.
      insert value TaskSpace( task = sy-index kbSize = 0 ) into table tasksWithSpace.
    enddo.
    "   2.: assign the component to the tasks (balanced by space).
    sort componentsWithSpaces by kbSize descending.
    assignComponents2Tasks( kbTotal ).
    sort TasksWithComponents by task ascending
                                kbSize descending
                                component ascending
                                partNo ascending.
  endmethod.

  method getComponentsWithSpaces.
*    if lines( componentsWithSpaces ) > 0 and    " already done, no update needed?
*       updCompsWithSpaces = abap_false.
*      return.
*    endif.
    data: calcTab type ALVLines,
          tables type standard table of tabname with default key.
    clear: componentsWithSpaces, kbTotal.
    calcTab = alvSelectedDatatab.
    if ( purpose <> 'Backup' and avoidRedundantExportImport = abap_true ).
      eliminateDuplicateTables( changing cCompsAndTables = calcTab ).
    endif.
    " Get the size of each component
    loop at calcTab reference into data(cLine).
      at new component.
        clear tables.
      endat.
      read table componentsWithSpaces reference into data(sC) with key component = cLine->component.
      if ( sy-subrc <> 0 ).
        insert cLine->tabname into table tables.
        insert value ComponentSpace(
            component = cLine->component
            tables = tables
            kbSize = cLine->sizekb )
            into table componentsWithSpaces.
      else.
        sC->kbSize = sc->kbSize + cLine->sizeKb.
        insert cLine->tabname into table sC->tables.
      endif.
      add cLine->sizeKb to kbTotal.
    endloop.
  endmethod.

  method tablesOfComponentAsString.
    data: compAndTable type ComponentAndTable,
          whereCondsOfTable type TablesAndWhereConditions,
          table type tabname,
          tableHasWhereCond type abap_bool,
          tAndWs type ref to TablesAndWhereConditions.
    clear result.
    get reference of whereCondsOfTable into tAndWs.
    compAndTable-component = iTaskComponent-component.
    " Iterate the tables in this task/component and build a single
    "   string, where the tables are separated by comma.
    loop at iTaskComponent-tables into compAndTable-table.
      " Get the data for tables needing a WHERE condition / a special SELECT.
      clear tAndWs->*.
      tableHasWhereCond = abap_false.
      if line_exists( tablesWithWhereCondition[ component = iTaskComponent-component table = compAndTable-table ] ).
        tableHasWhereCond = abap_true.
        add 1 to cCntWhere.
        getWhereCondition4SpecialTable(
            exporting iCompAndTable = compAndTable
                      i4SelOrR3trans = 'R'
            changing cTablesAndWhereConds = tAndWs ).
        insert lines of tAndWs->* into table cWhereCondsOfComponent.
      endif.
      if ( iNotWithWhereCond = abap_true and tableHasWhereCond = abap_true ).
        continue.
      endif.
      " Concatenate all tables in a single string, separated by ','
      add 1 to cCntTables.
      if ( result is initial ).
        result = compAndTable-table.
      else.
        concatenate result ',' compAndTable-table into result.
      endif.
    endloop.
  endmethod.

  method addWhereConditions2Xml.
    loop at iTablesAndWhereConds reference into data(tWC).
      if sy-tabix = 1.
        addXmlLine( |                <WhereCondition>| ).
      endif.
      addXmlLine( |                    <Table>{ tWC->table }</Table>| ).
      if ( not tWC->r3transcmd is initial ).
        addXmlLine( |                    <WhereCond>{ tWC->r3transCmd }</WhereCond>| ).
      else.
        addXmlLine( |                    <WhereCond>{ tWC->whereCond }</WhereCond>| ).
      endif.
    endloop.
    if ( lines( iTablesAndWhereConds ) > 0 ).
      addXmlLine( |                </WhereCondition>| ).
    endif.
  endmethod.

  method getCommentLine4Task.
    if ( iTaskComponent-partNo > 0 ).
      result = |{ exportImportRemove } { iTaskComponent-component } part { iTaskComponent-partNo }</Comment>|.
    else.
      result = |{ exportImportRemove } { iTaskComponent-component }</Comment>|.
    endif.
  endmethod.

  method eliminateDuplicateTables.
    data: allTables type sorted table of tabname
              with unique default key,
          cAndT type ComponentAndTable,
          lines2BeDeleted type standard table of ComponentAndTable
              with default key,
          comps2BeDeleted type standard table of ECH_DTE_COMPONENT
              with default key.
    sort cCompsAndTables by component tabname.
    pushBackCompsCvrdInOtherComps( changing cCompsAndTables = cCompsAndTables ).
    " Iterate the components. If a table (without WHERE condition)
    "   is processed in a component before, the table is to be
    "   deleted from the current component.
    loop at cCompsAndTables reference into data(ct).
      cAndT-component = ct->component.
      cAndT-table = ct->tabname.
      if ( not line_exists( tablesWithWhereCondition[ component = cAndT-component table = cAndT-table ] ) ).
        if ( line_exists( allTables[ table_line = cAndT-table ] ) ).
          insert cAndT into table lines2BeDeleted.
        else.
          insert cAndT-table into table allTables.
        endif.
      endif.
    endloop.
    if ( lines( lines2BeDeleted ) > 0 ).
      loop at lines2BeDeleted reference into data(d).
        delete cCompsAndTables where component = d->component
                                 and tabname = d->table.
      endloop.
    endif.
  endmethod.

  method pushBackCompsCvrdInOtherComps.
    data: ownSortOrder type OwnSortOrder,
          cAndTInNewOrder type standard table of OwnSortOrder
              with default key,
          tabAlsoInOtherComp type standard table of CompAndTableWithFlag
              with default key,
          foundInOtherComp type abap_bool,
          allTablesAlsoInOtherComp type abap_bool,
          compCoveredInOtherComp type standard table of ECH_DTE_COMPONENT
              with default key.
    " Determine whether a table (without WHERE condition) of a component is also part
    "   of another component (and there also without WHERE condition).
    loop at cCompsAndTables reference into data(cT).
      foundInOtherComp = abap_false.
      if not line_exists( tablesWithWhereCondition[ component = cT->component table = cT->tabname ] ).
        loop at cCompsAndTables transporting no fields
            where component <> cT->component
              and tabname = cT->tabname.
          if not line_exists( tablesWithWhereCondition[ component = cT->component table = cT->tabname ] ).
            foundInOtherComp = abap_true.
            exit.
          endif.
        endloop.
      endif.
      insert value CompAndTableWithFlag( component = cT->component
          table = cT->tabname
          flag = foundInOtherComp ) into table tabAlsoInOtherComp.
    endloop.
    " Now determine the components where _all_ tables are covered in other components.
    sort tabAlsoInOtherComp by component table.
    loop at tabAlsoInOtherComp reference into data(tCvrd).
      at new component.
        allTablesAlsoInOtherComp = abap_true.
      endat.
      if tCvrd->flag = abap_false.
        allTablesAlsoInOtherComp = abap_false.
      endif.
      at end of component.
        if ( allTablesAlsoInOtherComp = abap_true ).
          insert tCvrd->component into table compCoveredInOtherComp.
        endif.
      endat.
    endloop.
    " Now new sort order: push back the components where all tables are covered
    "   also in other components. Likely for these components no export / import
    "   is necessary.
    loop at cCompsAndTables reference into cT.
      if ( line_exists( compCoveredInOtherComp[ table_line = cT->component ] ) ).
        ownSortOrder-no = 2.
      else.
        ownSortOrder-no = 1.
      endif.
      ownSortOrder-alvLine = cT->*.
      insert ownSortOrder into table cAndTInNewOrder.
    endloop.
    sort cAndTInNewOrder by no alvLine-component alvLine-tabname.
    clear cCompsAndTables.
    loop at cAndTInNewOrder reference into data(cTNewOrder).
      insert cTNewOrder->alvLine into table cCompsAndTables.
    endloop.
  endmethod.

  method assignComponents2Tasks.
    data: kbThreshold type f,
          compAndTable type ComponentAndTable,
          taskComponent type TaskComponent.
    " If a component's size is > (average space of a task * 1.2), there is an option
    "   to split the component into pieces.
    kbThreshold = FACTOR4SPLITTING * iTotalKbSize / parallelTasks.
    loop at componentsWithSpaces reference into data(sC).
      if ( sC->kbSize > kbThreshold and
           not line_exists( componentsNot2BeSplitted[ table_line = sC->component ] ) ).
        if ( splitBigComponents = abap_true ).
          splitComponent( iTotalKbSize = iTotalKbSize iComponentSpace = sC->* ).
          continue.
        endif.
      endif.
      " Component is not to be splitted: add it (with all of its tables) to the task with the lowest size.
      taskComponent-task = 0.
      taskComponent-partNo = 0.
      taskComponent-component = sC->component.
      taskComponent-tables = sC->tables.
      taskComponent-kbSize = sC->kbsize.
      addComponent2Task( taskComponent ).
    endloop.
  endmethod.

  method splitComponent.
    data: kbSplittedPart            type f,
          taskComponent             type TaskComponent,
          tablesOfSplittedComponent type sorted table of tabname with unique default key,
          spacePerTable             type SpacePerTable,
          kbSizeOfTable             type i,
          currentPartOfComponent    type i.
    " Get the tables of the component to be splitted with their sizes.
    loop at iComponentSpace-tables reference into data(cS).
      loop at alvSelectedDataTab reference into data(alv)
          where component = iComponentSpace-component and tabname = cS->*.
        kbSizeOfTable = alv->sizekb.
        insert value TableSpace( table = cS->* kbSize = alv->sizeKb )
            into table spacePerTable.
      endloop.
    endloop.
    sort spacePerTable by kbSize descending.
    loop at spacePerTable reference into data(spaceT).
      if ( not line_exists( tablesOfSplittedComponent[ table_line = spaceT->table ] ) ).
        insert spaceT->table into table tablesOfSplittedComponent.
      endif.
      add spaceT->kbSize to kbSplittedPart.
      if ( kbSplittedPart >= ( iTotalKbsize / parallelTasks ) ).
        taskComponent-task = 0.
        add 1 to taskComponent-partNo.
        taskComponent-component = iComponentSpace-component.
        taskComponent-tables = tablesOfSplittedComponent.
        taskComponent-kbSize = kbSplittedPart.
        addComponent2Task( taskComponent ).
        clear: kbSplittedPart, tablesOfSplittedComponent.
      endif.
    endloop.
    " Remaining tables for this component:
    if lines( tablesOfSplittedComponent ) > 0.
      taskComponent-task = 0.
      add 1 to taskComponent-partNo.
      taskComponent-component = iComponentSpace-component.
      taskComponent-tables = tablesOfSplittedComponent.
      taskComponent-kbSize = kbSplittedPart.
      addComponent2Task( taskComponent ).
      clear: kbSplittedPart, tablesOfSplittedComponent.
    endif.
  endmethod.

  method addComponent2Task.
    " Add a component (either with all of its tables or a part of them) to
    "   the task with the lowest amount of data.
    sort tasksWithSpace by kbSize ascending.
    read table tasksWithSpace index 1 reference into data(tS).
    insert value TaskComponent( task = tS->task
                                component = iTaskComponent-component
                                partNo = iTaskComponent-partNo
                                tables = iTaskComponent-tables
                                kbSize = iTaskComponent-kbsize )
        into table tasksWithComponents.
    tS->kbSize = tS->kbSize + iTaskComponent-kbsize.
    tS->components = tS->components + 1.
  endmethod.

  method addXmlLine.
    insert iLine into table xmlFileLines.
  endmethod.

  method getSelectedALVData.
    clear: result, eNumberOfComponents.
    data: exclTable type ExcludedTable.
    me->get_selected_rows( importing et_index_rows = selectedRows ).
    me->get_filtered_entries( importing et_filtered_entries = filteredRows ).
    loop at alvDatatab reference into data(sd).
      if ( isInSelection( sy-tabix ) = abap_true ).
        insert sd->* into table result.
      endif.
    endloop.
    loop at tables2BeExcluded into exclTable.
      delete result where tabname = exclTable-table.
      addToExcludedTables( exporting iTable = exclTable-table
                                     iReason = exclTable-reason ).
    endloop.
    data: comps type sorted table of ECH_DTE_COMPONENT with unique default key.
    loop at result reference into data(r).
      if not line_exists( comps[ table_line = r->component ] ).
        insert r->component into table comps.
      endif.
    endloop.
    eNumberOfComponents = lines( comps ).
  endmethod.

  method isInSelection.
    result = abap_false.
    " Line is filtered out of the list?
    if ( line_exists( filteredRows[ table_line = iIndex ] ) ).
      result = abap_false.
      return.
    endif.
    if ( lines( selectedRows ) > 0 ).
      if not line_exists( selectedRows[ index = iIndex ] ).
        result = abap_false.
        return.
      endif.
    endif.
    result = abap_true.
  endmethod.

  method getXML4MaxWPRuntimeExtend.
    data: xmlFileLinesBackup type StringTable.
    xmlFileLinesBackup = xmlFileLines.
    clear xmlFileLines.
    addXmlLine( |    <Task>| ).
    addXmlLine( |        <InsertProgram StopOnError="true">| ).
    addXmlLine( |            <Comment>Extend max. WP runtime</Comment>| ).
    if pW3H = abap_true.
      addXmlLine( |            <ABAPProgram>ZSC4SAP_SR_MAXWPRT_3H</ABAPProgram>| ).
      addXmlLine( |            <ProgramTitle>Set max. WP runtime temporarily to 3 hours</ProgramTitle>| ).
      addXmlLine( |            <SourceFile>$Sc4SAP$SysRefr_MAX_WP_RT_3H</SourceFile>| ).
    else.
      addXmlLine( |            <ABAPProgram>ZSC4SAP_SR_MAXWPRT_UNLTD</ABAPProgram>| ).
      addXmlLine( |            <ProgramTitle>Set max. WP runtime temporarily to unlimited</ProgramTitle>| ).
      addXmlLine( |            <SourceFile>$Sc4SAP$SysRefr_MAX_WP_RT_UNLTD</SourceFile>| ).
    endif.
    addXmlLine( |            <Overwrite>true</Overwrite>| ).
    addXmlLine( |            <Execute>true</Execute>| ).
    addXmlLine( |        </InsertProgram>| ).
    addXmlLine( |    </Task>| ).
    result = xmlFileLines.
    xmlFileLines = xmlFileLinesBackup.
  endmethod.

  method getXML4MaxWPRuntimeDefault.
    data: xmlFileLinesBackup type StringTable.
    xmlFileLinesBackup = xmlFileLines.
    clear xmlFileLines.
    addXmlLine( |    <Task>| ).
    addXmlLine( |        <InsertProgram StopOnError="true">| ).
    addXmlLine( |            <Comment>Set max. WP runtime back to default</Comment>| ).
    addXmlLine( |            <ABAPProgram>ZSC4SAP_SR_MAXWPRT_DEF</ABAPProgram>| ).
    addXmlLine( |            <ProgramTitle>Set max. WP runtime back to default value</ProgramTitle>| ).
    addXmlLine( |            <SourceFile>$Sc4SAP$SysRefr_MAX_WP_RT_DEF</SourceFile>| ).
    addXmlLine( |            <Overwrite>true</Overwrite>| ).
    addXmlLine( |            <Execute>true</Execute>| ).
    addXmlLine( |        </InsertProgram>| ).
    addXmlLine( |    </Task>| ).
    result = xmlFileLines.
    xmlFileLines = xmlFileLinesBackup.
  endmethod.

  method getWhereCondition4SpecialTable.
    " Source of information: function module SCTC_REFRESH_EXPORT_TAB_COMP
    data: dq type c.    " double quotation character
    clear cTablesAndWhereConds->*.
    " For 'R'3trans: put the field names in double quotation marks.
    " For 'S'elect: use field names without quotation marks.
    if i4SelOrR3trans = 'R'.
      dq = '"'.
    endif.
    case iCompAndTable-table.
      when 'NRIV'.
        getWhereCond4NRIV(
            exporting iComponent = iCompAndTable-component
                      iQMark = dq
            changing cTablesAndWhereConds = cTablesAndWhereConds ).
      when 'TADIR'.
        getWhereCond4TADIR(
            exporting iComponent = iCompAndTable-component
                      iQMark = dq
            changing cTablesAndWhereConds = cTablesAndWhereConds ).
      when 'DOKIL'.
        getWhereCond4DOKIL(
            exporting iComponent = iCompAndTable-component
                      iQMark = dq
            changing cTablesAndWhereConds = cTablesAndWhereConds ).
     endcase.
  endmethod.

  method getWhereCond4NRIV.
    clear cTablesAndWhereConds->*.
    case iComponent.
      when 'SWU3' or 'SWU3_DATA'.
        insert value TableAndWhereCondition( table = 'NRIV'
            whereCond = |{ iQMark }OBJECT{ iQMark } = 'SWE_EVTID'| ) into table cTablesAndWhereConds->*.
        insert value TableAndWhereCondition( table = 'NRIV'
            whereCond = |{ iQMark }OBJECT{ iQMark } = 'SWW_WIID'| ) into table cTablesAndWhereConds->*.
      when 'SAP_OFFICE'.
        insert value TableAndWhereCondition( table = 'NRIV'
            whereCond = |{ iQMark }OBJECT{ iQMark } = 'SO_OBJ_USR'| ) into table cTablesAndWhereConds->*.
        insert value TableAndWhereCondition( table = 'NRIV'
            whereCond = |{ iQMark }OBJECT{ iQMark } = 'SO_OBJ_ADR'| ) into table cTablesAndWhereConds->*.
        insert value TableAndWhereCondition( table = 'NRIV'
            whereCond = |{ iQMark }OBJECT{ iQMark } = 'SO_OBJ_FOL'| ) into table cTablesAndWhereConds->*.
        insert value TableAndWhereCondition( table = 'NRIV'
            whereCond = |{ iQMark }OBJECT{ iQMark } = 'SO_OBJ_DLI'| ) into table cTablesAndWhereConds->*.
      when 'OFFICE_ATT'.
        insert value TableAndWhereCondition( table = 'NRIV'
            whereCond = |{ iQMark }OBJECT{ iQMark } = 'SO_OBJ_RAW'| ) into table cTablesAndWhereConds->*.
      when others.
        message |NRIV: full content is to be processed in component { iComponent }. Please check!| type 'W'.
    endcase.
  endmethod.

  method getWhereCond4TADIR.
    clear cTablesAndWhereConds->*.
    case iComponent.
      when 'ALECUST'.
        insert value TableAndWhereCondition( table = 'TADIR'
            whereCond = |{ iQMark }PGMID{ iQMark } = 'R3TR' and { iQMark }OBJECT{ iQMark } = 'IDOC'| )
            into table cTablesAndWhereConds->*.
      when 'TMS'.
        insert value TableAndWhereCondition( table = 'TADIR'
            whereCond = |{ iQMark }PGMID{ iQMark } = 'HEAD' and { iQMark }OBJECT{ iQMark } = 'SYST'| )
            into table cTablesAndWhereConds->*.
      when 'SMW0'.
        insert value TableAndWhereCondition( table = 'TADIR'
            whereCond = |{ iQMark }PGMID{ iQMark } = 'R3TR' and { iQMark }OBJECT{ iQMark } = 'W3HT'| )
            into table cTablesAndWhereConds->*.
      when others.
        message |TADIR: full content is to be processed in component { iComponent }. Please check!| type 'W'.
    endcase.
  endmethod.

  method getWhereCond4DOKIL.
    clear cTablesAndWhereConds->*.
    case iComponent.
      when 'LOGINSCREEN'.
        insert value TableAndWhereCondition( table = 'DOKIL'
            whereCond  = |{ iQMark }ID{ iQMark } = 'TX' and { iQMark }OBJECT{ iQMark } = 'ZLOGIN_SCREEN_INFO'|
            r3transCmd = |$Sc4SAPCmd$select docu TXZLOGIN_SCREEN_INFO| ) into table cTablesAndWhereConds->*.
      when others.
        message |DOKIL: full content is to be processed in component { iComponent }. Please check!| type 'W'.
    endcase.
  endmethod.

  method genCallBeforeExpAddress3.
    if beforeUserExportDone = abap_true.
      return.
    endif.
    " When component USER is to be splitted: create a separate XML file
    "   containing the task to be done before user export.
    "   Otherwise add the before user export stuff to the current XML file.
    if ( pUSSplit = 'X' and iTaskComponent-partno > 0 ).
      createXML4BeforeUserExport( ).
    else.
      insert lines of getXML4BeforeUserExport( ) into table xmlFileLines.
    endif.
    beforeUserExportDone = abap_true.
  endmethod.

  method genCallAfterImpAddress3.
    if afterUserImportDone = abap_true.
      return.
    endif.
    " When component USER is to be splitted: create a separate XML file
    "   containing the task to be done after user import.
    "   Otherwise add the after user import stuff to the current XML file.
    if ( pUSSplit = 'X' and iTaskComponent-partno > 0 ).
      createXML4AfterUserImport( ).
    else.
      insert lines of getXML4AfterUserImport( ) into table xmlFileLines.
    endif.
    afterUserImportDone = abap_true.
  endmethod.

  method getXML4BeforeUserExport.
    data: xmlFileLinesBackup type StringTable.
    xmlFileLinesBackup = xmlFileLines.
    clear xmlFileLines.
    addXmlLine( |    <Task>| ).
    addXmlLine( |        <InsertProgram StopOnError="true">| ).
    addXmlLine( |            <Comment>Fill shadow tables for component USER</Comment>| ).
    addXmlLine( |            <ABAPProgram>ZSC4SAP_SR_EXPADDRESS3</ABAPProgram>| ).
    addXmlLine( |            <ProgramTitle>Call BEFORE_EXP_ADDRESS3 in the context of system refreshes</ProgramTitle>| ).
    addXmlLine( |            <SourceFile>$Sc4SAP$SysRefr_BEFORE_EXP_ADDRESS3</SourceFile>| ).
    addXmlLine( |            <Overwrite>true</Overwrite>| ).
    addXmlLine( |            <Execute>true</Execute>| ).
    addXmlLine( |        </InsertProgram>| ).
    addXmlLine( |    </Task>| ).
    result = xmlFileLines.
    xmlFileLines = xmlFileLinesBackup.
  endmethod.

  method getXML4AfterUserImport.
    data: xmlFileLinesBackup type StringTable.
    xmlFileLinesBackup = xmlFileLines.
    clear xmlFileLines.
    addXmlLine( |    <Task>| ).
    addXmlLine( |        <InsertProgram StopOnError="true">| ).
    addXmlLine( |            <Comment>Process shadow tables for component USER after Import</Comment>| ).
    addXmlLine( |            <ABAPProgram>ZSC4SAP_SR_IMPADDRESS3</ABAPProgram>| ).
    addXmlLine( |            <ProgramTitle>Call AFTER_IMP_ADDRESS3 in the context of system refreshes</ProgramTitle>| ).
    addXmlLine( |            <SourceFile>$Sc4SAP$SysRefr_AFTER_IMP_ADDRESS3</SourceFile>| ).
    addXmlLine( |            <Overwrite>true</Overwrite>| ).
    addXmlLine( |            <Execute>true</Execute>| ).
    addXmlLine( |        </InsertProgram>| ).
    addXmlLine( |    </Task>| ).
    result = xmlFileLines.
    xmlFileLines = xmlFileLinesBackup.
  endmethod.

  method createXML4BeforeUserExport.
    data: xmlLine type string,
          xmlFileLinesBackup type StringTable,
          filename type string,
          filenameSuffix type string.
    xmlFileLinesBackup = xmlFileLines.
    clear xmlFileLines.
    addXmlLine('<ExecutionChain>').
    addXmlLine( |    <Comment>Fill shadow tables before export of component USER</Comment>| ).
    xmlLine = |    <DefaultConnection>{ connection }</DefaultConnection>|.
    addXmlLine( xmlLine ).
    addXmlLine( |    <Resumption>true</Resumption>| ).
    insert lines of getXML4BeforeUserExport( ) into table xmlFileLines.
    addXmlLine('</ExecutionChain>').
    try.
      if ( xmlFileAbsPath is initial ).
        ask4DownloadPath( ).
      endif.
      filename = replace( val = xmlFileAbsPath sub = '.xml' with = '' ).
      filenameSuffix = |BeforeUserExport.xml|.
      filename = |{ filename }_{ filenameSuffix }|.
      downloadXMLFile( iFilename = filename ).
    catch zcl_exc_PCATables into data(exc2).
      " message exc2->text type 'I'.  " When user canceled the file dialog.
    endtry.
    xmlFileLines = xmlFileLinesBackup.
  endmethod.

  method createXML4AfterUserImport.
    data: xmlLine type string,
          xmlFileLinesBackup type StringTable,
          filename type string,
          filenameSuffix type string.
    xmlFileLinesBackup = xmlFileLines.
    clear xmlFileLines.
    addXmlLine('<ExecutionChain>').
    addXmlLine( |    <Comment>Process shadow tables after import of component USER</Comment>| ).
    xmlLine = |    <DefaultConnection>{ connection }</DefaultConnection>|.
    addXmlLine( xmlLine ).
    addXmlLine( |    <Resumption>true</Resumption>| ).
    insert lines of getXML4AfterUserImport( ) into table xmlFileLines.
    addXmlLine('</ExecutionChain>').
    try.
      if ( xmlFileAbsPath is initial ).
        ask4DownloadPath( ).
      endif.
      filename = replace( val = xmlFileAbsPath sub = '.xml' with = '' ).
      filenameSuffix = |AfterUserImport.xml|.
      filename = |{ filename }_{ filenameSuffix }|.
      downloadXMLFile( iFilename = filename ).
    catch zcl_exc_PCATables into data(exc2).
      " message exc2->text type 'I'.  " When user canceled the file dialog.
    endtry.
    xmlFileLines = xmlFileLinesBackup.
  endmethod.

  method createXML4WPRuntimeExtend.
    data: xmlLine type string,
          xmlFileLinesBackup type StringTable,
          filename type string,
          filenameSuffix type string.
    xmlFileLinesBackup = xmlFileLines.
    clear xmlFileLines.
    addXmlLine('<ExecutionChain>').
    addXmlLine( |    <Comment>Extend WP Runtime maximum (might be necessary for processing huge components)</Comment>| ).
    xmlLine = |    <DefaultConnection>{ connection }</DefaultConnection>|.
    addXmlLine( xmlLine ).
    insert lines of getXML4MaxWPRuntimeExtend( ) into table xmlFileLines.
    addXmlLine('</ExecutionChain>').
    try.
      if ( xmlFileAbsPath is initial ).
        ask4DownloadPath( ).
      endif.
      filename = replace( val = xmlFileAbsPath sub = '.xml' with = '' ).
      filenameSuffix = |ExtendMaxWPRuntime.xml|.
      filename = |{ filename }_{ filenameSuffix }|.
      downloadXMLFile( iFilename = filename ).
    catch zcl_exc_PCATables into data(exc2).
      " message exc2->text type 'I'.  " When user canceled the file dialog.
    endtry.
    xmlFileLines = xmlFileLinesBackup.
  endmethod.

  method createXML4WPRuntimeDefault.
    data: xmlLine type string,
          xmlFileLinesBackup type StringTable,
          filename type string,
          filenameSuffix type string.
    xmlFileLinesBackup = xmlFileLines.
    clear xmlFileLines.
    addXmlLine('<ExecutionChain>').
    addXmlLine( |    <Comment>Set WP Runtime maximum back to default value</Comment>| ).
    xmlLine = |    <DefaultConnection>{ connection }</DefaultConnection>|.
    addXmlLine( xmlLine ).
    insert lines of getXML4MaxWPRuntimeDefault( ) into table xmlFileLines.
    addXmlLine('</ExecutionChain>').
    try.
      if ( xmlFileAbsPath is initial ).
        ask4DownloadPath( ).
      endif.
      filename = replace( val = xmlFileAbsPath sub = '.xml' with = '' ).
      filenameSuffix = |DefaultMaxWPRuntime.xml|.
      filename = |{ filename }_{ filenameSuffix }|.
      downloadXMLFile( iFilename = filename ).
    catch zcl_exc_PCATables into data(exc2).
      " message exc2->text type 'I'.  " When user canceled the file dialog.
    endtry.
    xmlFileLines = xmlFileLinesBackup.
  endmethod.

  method determineSAPPathSeparator.   " Get the path separator for the current OS.
    if ( sy-opsys cs 'Win' ).
      pathSeparator = '\'.
    else.
      pathSeparator = '/'.
    endif.
    " Add path separator to variable for R3trans files if missing.
    if ( not path4R3transFiles CP |*{ pathSeparator }|  and
         not path4R3transFiles CP |*$| ).
      concatenate path4R3transFiles pathSeparator into path4R3transFiles.
    endif.
  endmethod.

  method specifySpecialTables.
    " Some tables need special handling and must not be copied with all data!
    " -> see function module SCTC_REFRESH_EXPORT_TAB_COMP.
    " For these tables WHERE conditions are to be specified.
    if lines( tablesWithWhereCondition ) > 0.   " already done?
      return.
    endif.
    addTableWithWhereCondition( iComponent = 'LOGINSCREEN' iTableName = 'DOKIL' ).
    " DOKIL is a combination of tables DOKIL, DOKHL and DOKTL (and to be processed
    "   in R3trans using 'DOKU' to make the confusion complete).
    addTableAlias( iComponent = 'LOGINSCREEN' iAlias = 'DOKIL' iTableName = 'DOKIL' ).
    addTableAlias( iComponent = 'LOGINSCREEN' iAlias = 'DOKIL' iTableName = 'DOKHL' ).
    addTableAlias( iComponent = 'LOGINSCREEN' iAlias = 'DOKIL' iTableName = 'DOKTL' ).
    addTableWithWhereCondition( iComponent = 'SWU3' iTableName = 'NRIV' ).
    addTableWithWhereCondition( iComponent = 'SWU3_DATA' iTableName = 'NRIV' ).
    addTableWithWhereCondition( iComponent = 'SAP_OFFICE' iTableName = 'NRIV' ).
    addTableWithWhereCondition( iComponent = 'OFFICE_ATT' iTableName = 'NRIV' ).
    addTableWithWhereCondition( iComponent = 'ALECUST' iTableName = 'TADIR' ).
    addTableWithWhereCondition( iComponent = 'TMS' iTableName = 'TADIR' ).
    addTableWithWhereCondition( iComponent = 'SMW0' iTableName = 'TADIR' ).
    " For tables with a WHERE condition a warning has to be given in case they appear
    "   in another component without a WHERE condition.
    loop at tablesWithWhereCondition reference into data(tW).
      if not line_exists( tables4WarningWithFullContent[ table_line = tW->table ] ).
        insert tW->table into table tables4WarningWithFullContent.
      endif.
    endloop.
  endmethod.

  method specifyComponents4ClassicMode.
    showProgressInfo( iText = 'Determine components for PCA classic mode...' ).
    data: comp type ECH_DTE_COMPONENT.
    " Add some fix defined components (according to the PCA tool,
    "   function module SCTC_REFRESH_GET_PCA_MODE).
    if lines( components4ClassicMode ) = 0.
      comp = 'TC_TASKRUN'.  insert comp into table components4ClassicMode.
      comp = 'TC_TASKVARI'. insert comp into table components4ClassicMode.
      comp = 'OFFICE_ATT'.  insert comp into table components4ClassicMode.
      comp = 'SNRO'.        insert comp into table components4ClassicMode.
      comp = 'ALECUST'.     insert comp into table components4ClassicMode.
      comp = 'TMS'.         insert comp into table components4ClassicMode.
      comp = 'SMW0'.        insert comp into table components4ClassicMode.
    endif.
    " PCA classic mode: use the R3trans control file for the commands at export.
    " New PCA mode: use a Transport of Copies containing the tables at export.
    " For using parallel=xx in R3trans a Transport of Copies is necessary.
    " But there might be components with tables, which can not be put into
    " a transport request. Also these components are to be managed with
    " PCA Classic mode. It is also possible to have a mix, means, using a ToC
    " for some tables and the control file for others, but here we do it like
    " the PCA tool does it: if a table of a component can not be put into a ToC,
    " we use the PCA classic mode for the whole component.
    checkTablesOfComp4ToC( ).
    showProgressInfo( iText = '...done' ).
  endmethod.

  method checkTablesOfComp4ToC.
    " Check whether the tables of the component can be put into a
    "   transport request (transport of copies). If not, the component
    "   is to be handled with PCA classic mode. Do not check tables with
    "   a given WHERE condition (like NRIV, TADIR), because WHERE conditions
    "   can not be managed in transport requests.
    data: selCompsAndTables type alvLines,
          trKorr type trkorr,
          comp type ECH_DTE_COMPONENT,
          compsTotal type i,
          compCnt type i,
          classicCheck type PCAClassicCheck,
          useClassicMode type abap_bool,
          showProgressInfo4Comp type abap_bool.
    call function 'TR_INSERT_NEW_COMM'
        exporting
          wi_kurztext          = 'Check component for new PCA mode'
          wi_trfunction        = 'T'
        importing
          we_trkorr            = trKorr
        exceptions
          no_systemname        = 1
          no_systemtype        = 2
          no_authorization     = 3
          e070_insert_error    = 4
          file_access_error    = 5
          order_lock_failed    = 6
          sap_range_full       = 7
          unallowed_trfunction = 8
          others               = 9.
    if sy-subrc <> 0.
      data(e) = new zcl_exc_PCATables( 'Transport of copies could not be created.' ).
      raise exception e.
    endif.
    selCompsAndTables = alvSelectedDataTab.
    sort selCompsAndTables by component tabname.
    " Determine amount of components (for having a total in the progress info).
    loop at selCompsAndTables reference into data(s).
      at new component.
        add 1 to compsTotal.
      endat.
    endloop.
    loop at selCompsAndTables reference into s.
      " In case the table has already been checked, just take the result.
      "   Otherwise, show an info that it is in progress.
      at new component.
        add 1 to compCnt.
        useClassicMode = abap_false.
        showProgressInfo4Comp = abap_true.
      endat.
      " In case it is already fixed that for the current component the PCA classic mode is to
      "   be used, we don't have to check its single tables.
      if line_exists( components4ClassicMode[ table_line = s->component ] ).
        continue.
      endif.
      " If we still use new PCA mode and if the table has not been checked yet, do it:
      "   For tables with WHERE clause no use of a transport of copies is possible, no check needed.
      "   But for other tables: if there is at least one that can not be added to a transport
      "   of copies, also the classic mode will be used.
      if useClassicMode = abap_false.
        if not line_exists( tablesWithWhereCondition[ component = s->component table = s->tabname ] ).
          read table pcaClassicChecks into classicCheck
              with key tabname = s->tabname.
          if sy-subrc = 0.
            useClassicmode = classicCheck-useClassicMode.
          else.
            if showProgressInfo4Comp = abap_true.
              showProgressInfo(
                  exporting iText = |Check component { s->component } for need to use PCA classic mode|
                            iMaxCnt = compsTotal
                            iCurrentCnt = compCnt ).
              showProgressInfo4Comp = abap_false.
            endif.
            if isTableUsableInToC( iTrKorr = trkorr iTableName = s->tabname ) = abap_false.
              useClassicmode = abap_true.
            endif.
            insert value PCAClassicCheck( tabname = s->tabname
                checked = abap_true
                useClassicMode = useClassicMode )
                into table pcaClassicChecks.
          endif.
        endif.
      endif.
      at end of component.
        " If for the component the PCA classic mode is to be used, add it to the internal table.
        if useClassicMode = abap_true and
            not line_exists( components4ClassicMode[ table_line = s->component ] ).
          insert s->component into table components4ClassicMode.
        endif.
      endat.
    endloop.
    " Transport request not needed anymore, delete it.
    delete from: e070 where trkorr = trKorr,
                 e071 where trkorr = trKorr,
                 e070c where trkorr = trKorr,
                 e070a where trkorr = trKorr.
    commit work.
  endmethod.

  method isTableUsableInToC.
    " Check whether a table can be put into a transport request (R3TR TABU <table>).
    data: e070Entries type standard table of e070,
          e070Record  type e070,
          e071Entries type standard table of e071,
          e071Record  type e071,
          e071KEntries type standard table of e071k.
    result = abap_true.
    e071Record-pgmid = 'R3TR'.
    e071Record-object = 'TABU'.
    e071Record-obj_name = iTablename.
    insert e071Record into table e071Entries.
    call function 'TR_REQUEST_CHOICE'
        exporting  iv_request_types     = '*'
                   iv_no_owner_check    = 'X'
                   iv_suppress_dialog   = abap_true
                   iv_request           = iTrkorr
                   it_e071              = e071Entries
                   it_e071k             = e071KEntries
        exceptions invalid_request      = 1
                   invalid_request_type = 2
                   user_not_owner       = 3
                   no_objects_appended  = 4
                   enqueue_error        = 5
                   cancelled_by_user    = 6
                   recursive_call       = 7
                   others               = 8.
    if sy-subrc <> 0.
      result = abap_false.
    endif.
  endmethod.

  method specifyComponentsNot2Split.
    data: comp type ECH_DTE_COMPONENT.
    " Component USER needs a pre- and a post-step (filling / processing
    "   the shadow tables) and therefore needs special handling. When the
    "   USER component is to be splitted, a separate XML file - executed
    "   before export resp. after import - is to be created.
    "   By default, do not split the USER component.
    if ( pUSSplit is initial ).
      if not line_exists( componentsNot2BeSplitted[ table_line = 'USER' ] ).
        comp = 'USER'. insert comp into table componentsNot2BeSplitted.
      endif.
    endif.
  endmethod.

  method addTableWithWhereCondition.
    data: tabWithWhere type ComponentAndTable.
    tabWithWhere-component = iComponent.
    tabWithWhere-table = iTableName.
    insert tabWithWhere into table tablesWithWhereCondition.
  endmethod.

  method addTableAlias.
    data: alias type ref to TableAlias,
          newTabnames type standard table of tabname with empty key.
    read table tableAliases with key component = iComponent alias = iAlias
        reference into alias.
    if sy-subrc = 0.
      if not line_exists( alias->tablenames[ table_line = iTablename ] ).
        insert iTablename into table alias->tablenames.
      endif.
    else.
      insert iTablename into table newTabnames.
      insert value TableAlias(
          component  = iComponent
          alias      = iAlias
          tablenames = newTabnames ) into table tableAliases.
    endif.
  endmethod.

  method specifyTables4Warning.
    " By default the PCA tools shows also the NRIV table (for components
    " NRIV and SNRO, means: complete!). This should result in a warning.
    " For some components there is a special handling with the NRIV table.
    " In case the NRIV table occurs in the list with another component a
    " warning will be given.
    if lines( tables4Warning ) > 0.   " already done?
      return.
    endif.
    if ( purpose <> 'Backup' ).
      addTable4Warning( iComponent = 'NRIV' iTableName = 'NRIV' ).
      addTable4Warning( iComponent = 'SNRO' iTableName = 'NRIV' ).
    endif.
  endmethod.

  method specifyTablesPossMissed.
    " There are some tables possibly not considered in (recent) PCA tool, but should
    "   (optionally).
    if action <> cv_truncate.
      if addSPATH = abap_true.
        addTabPossiblyMissed( iComponent = 'S_PATH_CONFIGURATION' iTableName = 'SPTH' ).
        addTabPossiblyMissed( iComponent = 'S_PATH_CONFIGURATION' iTableName = 'SPTHB' ).
        addTabPossiblyMissed( iComponent = 'S_PATH_CONFIGURATION' iTableName = 'SPTHT' ).
      endif.
    endif.
  endmethod.

  method setPurpose.
    purpose = iPurpose.
  endmethod.

  method setConnection.
    connection = iConnection.
  endmethod.

  method setPath4R3transFiles.
    path4R3transFiles = iPath.
  endmethod.

  method setAvoidRedundantExportImport.
    avoidRedundantExportImport = iValue.
  endmethod.

  method setParallelTasks.
    parallelTasks = iValue.
  endmethod.

  method setParallelR3Tasks.
    parallelR3Tasks = iValue.
  endmethod.

  method setSplitBigComponents.
    splitBigComponents = iValue.
  endmethod.

  method setWithoutNRIVSNRO.
    withoutNRIVSNRO = iValue.
  endmethod.

  method setAddSPATH.
    addSPATH = iValue.
  endmethod.

  method setRefreshOrTruncate.
    refreshOrTruncate = iValue.
  endmethod.

  method addTable4Warning.
    data: tab4Warning type ComponentAndTable.
    if ( not line_exists( tables4Warning[ component = iComponent table = iTablename ] ) ).
      tab4Warning-component = iComponent.
      tab4Warning-table = iTablename.
      insert tab4Warning into table tables4Warning.
    endif.
  endmethod.

  method addTabPossiblyMissed.
    data: tabMissing type ComponentAndTable.
    if ( not line_exists( tablesPossiblyMissedInPCA[ component = iComponent table = iTablename ] ) ).
      tabMissing-component = iComponent.
      tabMissing-table = iTablename.
      insert tabMissing into table tablesPossiblyMissedInPCA.
    endif.

  endmethod.

  method isConfirmedAfterWarning.
    result = abap_false.
    data: buttonPressed type c.
    call function 'POPUP_FOR_INTERACTION'
      EXPORTING
        HEADLINE       = |Warning: table { iCompAndTable-table } in component { iCompAndTable-component }|
        TEXT1          = 'The table is part of the selection and would be'
        TEXT2          = 'processed with all data in it.'
        TEXT3          = 'Do you really want to process the whole table?'
        TEXT4          = 'If not, press Cancel and de-select or use a filter'
        TEXT5          = 'to exclude table / component from processing.'
        TICON          = 'W'
        BUTTON_1       = 'Yes'
        BUTTON_2       = 'No / Cancel'
      IMPORTING
        BUTTON_PRESSED = buttonPressed.
    case buttonPressed.
        when 1.
          result = abap_true.
    endcase.
  endmethod.

  method addToExcludedTables.
    if not ( line_exists( exclTables[ table = iTable ] ) ).
      insert value ExcludedTable(
            table = iTable reason = iReason ) into table exclTables.
    endif.
  endmethod.

  method downloadXMLFile4Task.
    data: fsRc     type sysubrc,
          fsAction type i,
          winTitle type string,
          path     type string,
          filename type string,
          filenameSuffix type string.
    done = abap_false.
    if ( xmlFileAbsPath is initial ).
      try.
        ask4DownloadPath( ).
      catch zcl_exc_PCATables into data(exc).
        " message exc2->text type 'I'.  " When user canceled the file dialog.
        exit.
      endtry.
    endif.
    filename = replace( val = xmlFileAbsPath sub = '.xml' with = '' ).
    filenameSuffix = |_task{ iTask }.xml|.
    if parallelTasks = 1.
      if purpose <> 'Backup'.
        filename = |{ filename }_{ exportImportRemove }.xml|.
      else.
        filename = |{ filename }.xml|.
      endif.
    else.
      if purpose <> 'Backup'.
        filename = |{ filename }_{ exportImportRemove }_task{ iTask }.xml|.
      else.
        filename = |{ filename }_task{ iTask }.xml|.
      endif.
    endif.
    done = me->downLoadXMLFile( iFileName = filename ).
  endmethod.

  method downloadXMLFile.
    done = abap_false.
    call method cl_gui_frontend_services=>GUI_DOWNLOAD
      exporting
        filename                = iFilename
        filetype                = 'ASC'
      changing
        data_tab                = xmlFileLines
      exceptions
        FILE_WRITE_ERROR        = 1                    " Cannot write to file
        NO_BATCH                = 2                    " Cannot execute front-end function in background
        GUI_REFUSE_FILETRANSFER = 3                    " Incorrect Front End
        INVALID_TYPE            = 4                    " Invalid value for parameter FILETYPE
        NO_AUTHORITY            = 5                    " No Download Authorization
        UNKNOWN_ERROR           = 6                    " Unknown error
        HEADER_NOT_ALLOWED      = 7                    " Invalid header
        SEPARATOR_NOT_ALLOWED   = 8                    " Invalid separator
        FILESIZE_NOT_ALLOWED    = 9                    " Invalid file size
        HEADER_TOO_LONG         = 10                   " Header information currently restricted to 1023 bytes
        DP_ERROR_CREATE         = 11                   " Cannot create DataProvider
        DP_ERROR_SEND           = 12                   " Error Sending Data with DataProvider
        DP_ERROR_WRITE          = 13                   " Error Writing Data with DataProvider
        UNKNOWN_DP_ERROR        = 14                   " Error when calling data provider
        ACCESS_DENIED           = 15                   " Access to File Denied
        DP_OUT_OF_MEMORY        = 16                   " Not enough memory in data provider
        DISK_FULL               = 17                   " Storage medium is full.
        DP_TIMEOUT              = 18                   " Data provider timeout
        FILE_NOT_FOUND          = 19                   " Could not find file
        DATAPROVIDER_EXCEPTION  = 20                   " General Exception Error in DataProvider
        CONTROL_FLUSH_ERROR     = 21                   " Error in Control Framework
        NOT_SUPPORTED_BY_GUI    = 22                   " GUI does not support this
        ERROR_NO_GUI            = 23                   " GUI not available
        OTHERS                  = 24.
    if SY-SUBRC <> 0.
      MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
        WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
    else.
      done = abap_true.
    endif.
  endmethod.

  method ask4DownloadPath.
    data: fsRc     type sysubrc,
          fsAction type i,
          winTitle type string,
          path     type string.
    winTitle = 'Select file for generated XML'.
    if ( purpose = 'Backup' ).
      xmlFilename = |{ sy-sysid }_Backup.xml|.
    else.
      xmlFilename = |{ sy-sysid }_SystemRefresh.xml|.
    endif.
    cl_gui_frontend_services=>file_save_dialog(
        exporting
          window_title =  winTitle
          default_extension = 'xml'
          default_file_name = xmlFilename
          file_filter       = '(*.xml)|*.xml (XML file)'
        changing
          filename    = xmlFilename
          path        = path
          fullpath    =  xmlFileAbsPath
          user_action = fsAction
        exceptions
          CNTL_ERROR                = 1
          ERROR_NO_GUI              = 2
          NOT_SUPPORTED_BY_GUI      = 3
          INVALID_DEFAULT_FILE_NAME = 4
          OTHERS                    = 5 ).
    if sy-subrc <> 0.
      message ID SY-MSGID type SY-MSGTY number SY-MSGNO
          with SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
    endif.
    if ( fsAction = cl_gui_frontend_services=>action_cancel ).
      data(e1) = new zcl_exc_PCATables( 'Action canceled' ).
      raise exception e1.
    endif.
  endmethod.

  method infoPopupAfterXMLGeneration.
    data: popupLines type zcl_InfoPopup=>StringTable,
          singleLine type string,
          deselectedRows type i,
          compsInXmlFile type sorted table of ECH_DTE_COMPONENT
              with unique default key,
          compsInXmlFileCnt type i,
          tablesInXmlFileCnt type i,
          distinctTables type sorted table of tabname
            with unique default key.
    compsInXmlFileCnt = 0.
    tablesInXmlFileCnt = 0.
    loop at tasksWithComponents reference into data(tC).
      if ( not line_exists( compsInXmlFile[ table_line = tC->component ] ) ).
        insert tC->component into table compsInXmlFile.
        add 1 to compsInXmlFileCnt.
      endif.
      tablesInXmlFileCnt = tablesInXmlFileCnt + lines( tC->tables ).
      loop at tC->tables reference into data(t).
        if not ( line_exists( distinctTables[ table_line = t->* ] ) ).
          insert t->* into table distinctTables.
        endif.
      endloop.
    endloop.
    singleLine = |Components in XML file(s): { compsInXmlFileCnt }|.
    insert singleLine into table popupLines.
    singleLine = |Total tables: { tablesInXmlFileCnt }|.
    insert singleLine into table popupLines.
    singleLine = |Distinct tables: { lines( distinctTables ) }|.
    insert singleLine into table popupLines.
    if ( lines( selectedRows ) > 0 ).
      deselectedRows = lines( alvDatatab ) - lines( filteredRows ) - lines( selectedRows ).
    endif.
    if ( lines( exclTables ) > 0 or lines( filteredRows ) > 0 or deselectedRows > 0 ).
      singleLine = 'Some tables were not considered:'.
      insert singleLine into table popupLines.
    endif.
    loop at exclTables reference into data(excl).
      singleLine = |{ excl->table } { excl->reason }|.
      insert singleLine into table popupLines.
    endloop.
    if ( lines( filteredRows ) > 0 ).
      singleLine = |{ lines( filteredRows ) } suppressed by filter.|.
      insert singleLine into table popupLines.
    endif.
    if ( deselectedRows > 0 ).
      singleLine = |{ deselectedRows } rows de-selected.|.
      insert singleLine into table popupLines.
    endif.
    sort tasksWithSpace by task ascending.
    loop at tasksWithSpace reference into data(tS).
      if ( lines( tasksWithSpace ) > 1 ).
        singleLine = |Task { tS->task } processes { tS->components } components with approx. { tS->kbsize } KB data|.
      else.
        singleLine = |{ tS->components } components with approx. { tS->kbsize } KB data|.
      endif.
      insert singleLine into table popupLines.
    endloop.
    zcl_InfoPopup=>init( ).
    zcl_InfoPopup=>show(
        exporting iTitle = 'XML file(s) downloaded'
                  iHeader = 'Information about components and tables:'
                  iLines = popupLines ).
  endmethod.

  method showDDicInfo.
    data: alvLine type TAlvLine.
    read table alvDataTab index iRow into alvLine.
    call function 'RS_TOOL_ACCESS'         ##FM_SUBRC_OK
      exporting
        operation    = 'SHOW'
        object_name  = alvLine-tabName
        object_type  = 'TABL'
      exceptions                   " Don't handle them
        not_executed        = 1
        invalid_object_type = 2
        others              = 3.
  endmethod.

endclass.

* The Event Handler for the ALV Grid
class EventHandler definition.
  public section.
    methods:
      constructor
        importing iAlv type ref to PCATablesALV,
      onToolbar for event toolbar of PCATablesALV
        importing e_object
                  e_interactive,
      onUserCommand for event user_command of PCATablesALV
        importing e_ucomm,
      afterUserCommand for event after_user_command OF PCATablesALV
        importing e_ucomm e_saved e_not_processed,
      onButtonClick for event button_click of PCATablesALV
        importing es_col_id
                  es_row_no.
  private section.
    data: alv type ref to PCATablesALV.
endclass.

class EventHandler implementation.
  method constructor.
    alv = ialv.
    if alv->gui_is_running <> ''.
      set handler me->onToolbar for alv.
      set handler me->onUserCommand for alv.
      set handler me->afterUserCommand for alv.
      set handler me->onButtonClick for alv.
      alv->register_edit_event(
          i_event_id = PCATablesALV=>mc_evt_enter ).
    endif.
  endmethod.
  " Add a button for XML file generation on the tool bar.
  method onToolbar.
    data: function    type UI_FUNC.
    field-symbols: <button> type stb_button.
    append value #( butn_type = 3 ) TO e_object->mt_toolbar.
    append value #( butn_type = 5
        text = 'XML file'
        icon = icon_generate
        function = 'XML'
        quickinfo = 'Generate XML file for command line tool'
        disabled = ' ' ) TO e_object->mt_toolbar.
  endmethod.
  " Handle click on the added button for generating an XML file.
  method onUserCommand.
    cl_gui_cfw=>dispatch( ).
    case e_ucomm.
      when 'XML'.
        alv->generateXMLFiles( ).
    endcase.
  endmethod.
  " Handle filtering the ALV list.
  method afterUserCommand.
    cl_gui_cfw=>dispatch( ).
    case e_ucomm.
      when '&MB_FILTER' or '&DELETE_FILTER' or '&FILTER'.
        alv->handleChangedFilter( ).
    endcase.
  endmethod.
  " Handle click on the DDic Info button.
  method onButtonClick.
    cl_gui_cfw=>dispatch( ).
    case es_col_id.
      when 'INFOBUTTON'.
        alv->showDDicInfo( es_row_no-row_id ).
    endcase.
  endmethod.
endclass.

class PCATablesList definition.
  public section.
    class-data: pcaTableList   type ref to PCATablesALV,
                alvEvents type ref to EventHandler,
                alvLayout type lvc_s_layo,
                alvVariant type disvariant.
    class-methods:
      show raising zcl_exc_PCATables.
endclass.

class PCATablesList implementation.
  method show.
    pcaTableList = new PCATablesALV(
        i_Parent = cl_gui_container=>default_screen
        i_Appl_Events = abap_true ).
    " The events are needed in dialog mode only. Registering
    "   events for an ALV grid in batch causes RAISE_EXCEPTION / CNTL_ERROR.
    if sy-batch ne 'X'.
      alvEvents = new EventHandler( pcaTableList ).
    endif.
    if ( refresh = 'X' ).
      pcaTableList->setRefreshOrTruncate( 'R' ).
    else.
      pcaTableList->setRefreshOrTruncate( 'T' ).
    endif.
    pcaTableList->setWithoutNRIVSNRO( pNRIV ).
    pcaTableList->setAddSPATH( pS_PATH ).
    if ( pBackup = 'X' ).
      pcaTableList->setPurpose( 'Backup' ).
    else.
      pcaTableList->setPurpose( 'SystemRefresh' ).
    endif.
    pcaTableList->setConnection( pConn ).
    pcaTableList->setPath4R3transFiles( ppath ).
    pcaTableList->setAvoidRedundantExportImport( pRedund ).
    pcaTableList->setParallelTasks( pTasks ).
    pcaTableList->setParallelR3Tasks( pR3Tasks ).
    pcaTableList->setSplitBigComponents( pBCsplit ).
    pcaTableList->getData( ).
    alvLayout-cwidth_opt = 'X'.
    alvLayout-stylefname = 'CELLTAB'.
    alvLayout-sel_mode = 'A'.  " Allow multiple rows selection
    alvLayout-info_fname = 'LINECOLOR'.
    alvVariant-report = sy-repid.
    pcaTableList->set_table_for_first_display(
      exporting is_layout = alvLayout
                is_variant = alvVariant
                i_save = 'A'
      changing  it_fieldcatalog = pcaTableList->fieldCatalog
                it_outtab       = pcaTableList->alvdatatab ).
    cl_gui_cfw=>flush( ).
    pcaTableList->handleChangedFilter( ).
    write:/ space.
  endmethod.
endclass.

" ============================================================
" Now: dealing with the selection screen and the users' input
constants: INPUT type c value '1',
           NOINPUT type c value '0'.
data: inputMissingComps type c value INPUT,
      inputRedund type c value INPUT,
      inputBCSplit type c value INPUT,
      inputUSSplit type c value INPUT,
      inputR3Parallel type c value INPUT,
      inputWPRt type c value NOINPUT,
      t000Cccoractiv   type CCCORACTIV,
      canceled         type abap_bool.

initialization.
  refresh = 'X'.   " Default: PCA tables for Refresh
  pSysref = 'X'.   " Default: XML files for System refresh
  pnriv = 'X'.     " Default: Do not include complete NRIV table.
  ltxt1 = 'List tables relevant for'.
  txt_r = 'Refresh'.
  txt_t = 'Data Cleanup'.
  txt_1 = 'Backup'.
  txt_2 = 'System refresh'.
  txt_s = 'Without components NRIV and SNRO'.
  ltxt_mc = 'Add missing components (if detected)'.
  txt_sp = 'S_PATH configuration'.
  txt_c = 'Connection'.
  txt_d = 'Path for R3trans files'.
  txt_m = 'Avoid multiple export/import of the same table'.
  txt_p = 'Number of parallel tasks (-> work processes)'.
  txt_3 = 'Number of parallel tasks (-> R3trans)'.
  txt_b = '  Split big components if necesssary for better balancing'.
  txt_u = '    Split USER component if necessary for better balancing'.
  txt_w = 'Set Max. WP Runtime temporarily to ...'.
  txt_h = '  3 hours'.
  txt_l = '  unlimited'.
  ltxt2 = 'Data for XML file generation'.
  nrivBtn  = ICON_INFORMATION.
  mCmp1Btn = ICON_INFORMATION.
  redBtn   = ICON_INFORMATION.
  tsksBtn  = ICON_INFORMATION.
  bcSpBtn  = ICON_INFORMATION.
  usSpBtn  = ICON_INFORMATION.
  r3pBtn   = ICON_INFORMATION.
  wpRtBtn  = ICON_INFORMATION.
  inputUSSplit = NOINPUT.
  perform enableFields.
  select single cccoractiv from T000 into t000Cccoractiv
      where MANDT = sy-mandt.

at selection-screen output.
  " Enable / disable some fields based on the chosen options
  if refresh is initial.
    inputMissingComps = NOINPUT.
    inputRedund = NOINPUT.
    inputR3Parallel = NOINPUT.
    inputBCSplit = NOINPUT.
    inputUSSplit = NOINPUT.
  else.
    if pBackup = 'X'.
      inputRedund = NOINPUT.
      inputBCSplit = NOINPUT.
      inputUSSplit = NOINPUT.
    else.
      inputRedund = INPUT.
      inputBCSplit = INPUT.
      if ( pBCSplit = 'X' ).
        inputUSSplit = INPUT.
      else.
        inputUSSplit = NOINPUT.
      endif.
    endif.
    inputMissingComps = INPUT.
    inputR3Parallel = INPUT.
  endif.
  if pWPRT is initial.
    inputWPRt = NOINPUT.
  else.
    inputWPRt = INPUT.
  endif.
  perform enableFields.

at selection-screen.
  case sy-ucomm.
    when 'BCSP'.
      if pBCSplit = 'X'.
        inputUSSplit = INPUT.
      else.
        inputUSSplit = NOINPUT.
        clear pUSSplit.
      endif.
      return.
    when 'NRI'.
      perform infoNRIV.
      return.
    when 'MC1'.
      perform infoS_PATH.
      return.
    when 'RED'.
      perform infoRedundTables.
      return.
    when 'TSKS'.
      perform infoTasksParallel.
      return.
    when 'USI'.
      perform infoUSERSplit.
      return.
    when 'BSI'.
      perform infoBigCompSplit.
      return.
    when 'R3P'.
      perform infoR3transParallel.
      return.
    when 'WPR'.
      perform infoMaxWPRuntime.
      return.
  endcase.
  if ( pTasks < 1 or pTasks > 50 ).
    message 'Number of parallel tasks (work processes): 1 to 50.' type 'E'.
  endif.
  if ( pR3tasks < 1 or pR3tasks > 10 ).
    message 'Number of parallel R3trans tasks : 1 to 10.' type 'E'.
  endif.
  if ( PR3tasks > 1 and t000Cccoractiv = 3 ).
    perform confirmClientSettings.
    if canceled = abap_true.
      message 'Action canceled' type 'E'.
    endif.
  endif.

form enableFields.
  loop at screen.
    case screen-name.
      when 'PS_PATH'.
        screen-input = inputMissingComps.
        modify screen.
      when 'PREDUND'.
        screen-input = inputRedund.
        modify screen.
      when 'PBCSPLIT'.
        screen-input = inputBCSplit.
        modify screen.
      when 'PUSSPLIT'.
        screen-input = inputUSSplit.
        modify screen.
      when 'PR3TASKS'.
        screen-input = inputR3Parallel.
        modify screen.
      when 'PW3H'.
        screen-input = inputWPRt.
        modify screen.
      when 'PWUNL'.
        screen-input = inputWPRt.
        modify screen.
    endcase.
  endloop.
  if inputMissingComps = '0'.
    clear ps_path.
  endif.
  if inputRedund = '0'.
    clear pRedund.
  endif.
  if inputBCSplit = '0'.
    clear: pBCSplit, pUSSplit.
  endif.
  if inputR3Parallel = '0'.
    pR3tasks = '1'.
  endif.
endform.

" Show some information related to the input fields
"   (triggered by pressing the 'i' buttons on the selection screen)
form infoNRIV.
  zcl_InfoPopup=>init( ).
  zcl_InfoPopup=>addLine( 'Usually it does not make sense for keeping the  ' ).
  zcl_InfoPopup=>addLine( 'NRIV table containing the number ranges (including' ).
  zcl_InfoPopup=>addLine( 'the number level) and consider them in Export / ' ).
  zcl_InfoPopup=>addLine( 'Import. The typically lower number levels in the' ).
  zcl_InfoPopup=>addLine( 'target system would have already numbers occupied' ).
  zcl_InfoPopup=>addLine( 'in data copied from the source system.           ' ).
  zcl_InfoPopup=>addLine( 'Therefore, this option is deactivated by default. ' ).
  zcl_InfoPopup=>show(
      exporting iTitle = 'Number Ranges'
                iHeader = 'Components NRIV and SNRO - Number Ranges' ).
endform.
form infoS_PATH.
  zcl_InfoPopup=>init( ).
  zcl_InfoPopup=>addLine( 'In the PCA tool (recently) the configuration tables ' ).
  zcl_InfoPopup=>addLine( 'for authorization object S_PATH are not considered. ' ).
  zcl_InfoPopup=>addLine( 'However, we think that these tables should be       ' ).
  zcl_InfoPopup=>addLine( 'considered for export and import, as these tables   ' ).
  zcl_InfoPopup=>addLine( 'typically contain paths / directories that are      ' ).
  zcl_InfoPopup=>addLine( 'system-specific.                                    ' ).
  zcl_InfoPopup=>addLine( 'SAP notes: 177702, 2370836, 2459510                 ' ).
  zcl_InfoPopup=>addLine( 'By activating this checkbox these tables will be    ' ).
  zcl_InfoPopup=>addLine( 'added, even if they are not considered in the PCA   ' ).
  zcl_InfoPopup=>addLine( 'tool.                                               ' ).
  zcl_InfoPopup=>show(
      exporting iTitle = 'Add S_PATH configuration if necessary'
                iHeader = 'Tables for authorization object S_PATH' ).
endform.
form infoRedundTables.
  zcl_InfoPopup=>init( ).
  zcl_InfoPopup=>addLine( 'Some components show an intersection of their   ' ).
  zcl_InfoPopup=>addLine( 'tables. By activating this flag, a table will be' ).
  zcl_InfoPopup=>addLine( 'exported / imported only once, even if it is    ' ).
  zcl_InfoPopup=>addLine( 'part of multiple components. Of course this     ' ).
  zcl_InfoPopup=>addLine( 'requires that _all_ exported components will be ' ).
  zcl_InfoPopup=>addLine( 'imported again for getting consistent data.     ' ).
  zcl_InfoPopup=>addLine( '-> www.shortcut-it.com/speed-up-the-system-refresh' ).
  zcl_InfoPopup=>show(
      exporting iTitle = 'Table redundancy in components'
                iHeader = 'Avoid exporting / importing tables redundantly' ).
endform.
form infoTasksParallel.
  zcl_InfoPopup=>init( ).
  zcl_InfoPopup=>addLine( 'For improving the performance you can divide the' ).
  zcl_InfoPopup=>addLine( 'processing of the components into more than 1 task' ).
  zcl_InfoPopup=>addLine( 'which can be processed in parallel. By this you ' ).
  zcl_InfoPopup=>addLine( 'can gain a significant lower runtime.           ' ).
  zcl_InfoPopup=>addLine( '-> www.shortcut-it.com/speed-up-the-system-refresh' ).
  zcl_InfoPopup=>show(
      exporting iTitle = 'Parallel tasks'
                iHeader = 'Using parallel tasks / multiple work processes' ).
endform.
form infoUSERSplit.
  zcl_InfoPopup=>init( ).
  zcl_InfoPopup=>addLine( 'Consider the necessary pre- and post-processing ' ).
  zcl_InfoPopup=>addLine( '(shadow tables to be filled / processed)!       ' ).
  zcl_InfoPopup=>addLine( 'For this 2 additional XML files will be created:' ).
  zcl_InfoPopup=>addLine( '- one to be processed before export             ' ).
  zcl_InfoPopup=>addLine( '- one to be processed after import              ' ).
  zcl_InfoPopup=>show(
      exporting iTitle = 'Important information'
                iHeader = 'Component USER needs pre- and post-processing' ).
endform.
form infoBigCompSplit.
  zcl_InfoPopup=>init( ).
  zcl_InfoPopup=>addLine( 'With this option enabled, big components will be' ).
  zcl_InfoPopup=>addLine( 'splitted into parts, that can be processed in   ' ).
  zcl_InfoPopup=>addLine( 'parallel. This does make sense only when you    ' ).
  zcl_InfoPopup=>addLine( 'specify more than 1 task to be used (input field' ).
  zcl_InfoPopup=>addLine( '''Number of parallel tasks (-> work processes)'')' ).
  zcl_InfoPopup=>show(
      exporting iTitle = 'Splitting big components'
                iHeader = '- Only useful when tasks > 1 - ' ).
endform.
form infoR3transParallel.
  zcl_InfoPopup=>init( ).
  zcl_InfoPopup=>addLine( 'R3trans can distribute its work into multiple   ' ).
  zcl_InfoPopup=>addLine( 'child processes. With this you can gain a       ' ).
  zcl_InfoPopup=>addLine( 'significant lower runtime in the import phase.  ' ).
  zcl_InfoPopup=>addLine( '-> www.shortcut-it.com/speed-up-the-system-refresh' ).
  zcl_InfoPopup=>addLine( 'For this the creation of transport requests should' ).
  zcl_InfoPopup=>addLine( 'be allowed in the client settings (SCC4: field    ' ).
  zcl_InfoPopup=>addLine( 'CCCORACTIV should not be set to 3 (= no transports' ).
  zcl_InfoPopup=>addLine( 'allowed)). ' ).
  zcl_InfoPopup=>show(
      exporting iTitle = 'Using parallelization of R3trans'
                iHeader = '- Effective at Import phase only - ' ).
endform.
form confirmClientSettings.
  data: answer type char1,
        title type string,
        line1 type string,
        line2 type string,
        line3 type string.
  canceled = abap_false.
  title = 'No transport requests allowed (-> SCC4)'.
  line1 = 'For using R3trans with parallel option the creation of'.
  line2 = 'transport requests should be allowed (-> SCC4).'.
  line3 = 'Use Cancel button to stop or confirm to go on.'.
  call function 'POPUP_TO_DECIDE'             ##FM_OLDED
      exporting defaultoption = '2'
                textline1     = line1
                textline2     = line2
                textline3     = line3
                text_option1  = 'Ok'
                text_option2  = 'Cancel'
                icon_text_option1 = 'ICON_SYSTEM_OKAY'
                icon_text_option2 = 'ICON_SYSTEM_CANCEL'
                titel         = title
      importing answer = answer.
  if ( answer = 'A' or answer = '2' ).           " Cancel?
    canceled = abap_true.
    exit.
  endif.
endform.
form infoMaxWPRuntime.
  zcl_InfoPopup=>init( ).
  zcl_InfoPopup=>addLine( 'For exporting / importing huge components it could be' ).
  zcl_InfoPopup=>addLine( 'necessary to increase the maximum runtime of DIA work' ).
  zcl_InfoPopup=>addLine( 'processes (profile parameter rdisp/max_wprun_time and' ).
  zcl_InfoPopup=>addLine( 'related). By activating this flag the maximum runtime' ).
  zcl_InfoPopup=>addLine( 'will be set temporarily to either 3 hours or unlimited' ).
  zcl_InfoPopup=>addLine( '(choose one of the options below).                    ' ).
  zcl_InfoPopup=>addLine( 'In case you do not use parallel tasks, this will be   ' ).
  zcl_InfoPopup=>addLine( 'built in into the XML file at the start and reverted  ' ).
  zcl_InfoPopup=>addLine( 'back to the default values at the end.                ' ).
  zcl_InfoPopup=>addLine( 'If you use parallel tasks, you have to call the SC4SAP' ).
  zcl_InfoPopup=>addLine( 'command line tool on your own with the additionally   ' ).
  zcl_InfoPopup=>addLine( 'created XML files at the start and at the end of the  ' ).
  zcl_InfoPopup=>addLine( 'processing.                                           ' ).
  zcl_InfoPopup=>show(
      exporting iTitle = 'Extend maximum runtime of work processes'
                iHeader = '- Possibly necessary for huge components - ' ).
endform.

" Create and show the list of PCA tables
start-of-selection.
  data: exc type ref to zcl_exc_PCATables.
  try.
    PCATablesList=>show( ).
  catch zcl_exc_PCATables into exc.
    message exc type 'E'.
  endtry.