Monday, March 16, 2015

ALV Tree Refresh (Delete all Nodes) - The Node Key Problem

Recently i stumbled across a problem in the ALV Tree. When you refresh the Tree you are supposed to delete all nodes

CALL METHOD REF_TREE->DELETE_ALL_NODES.

and add the new Nodes after. The problem here is, that the Tree implementation does not reset the  Node Key Counter. So when you had 248 Elements before the new Tree will start at Key 249(-1?).

The thing is, i wanted to have the same UI after the refresh, meaning all the expanded Nodes should be expanded again. You can read expanded Nodes with REF_TREE->GET_EXPANDED_NODES but it will only give you a list of Keys, which are pretty worthless after the Refresh if you dont want to do complicated calculations, which might fail due to complexity.

You can later Expand the Nodes in the new tree with REF_TREE->EXPAND_NODES. But now we need a connection between the old node keys and the new ones.

Given that you have an itab it_data with unique keys that builds up the tree ist is possible by using that table and an extra itab l_it_expanded with the same structure that holds the expanded data lines instead of only the node keys.


  1. First you read all the expanded nodes GET_EXPANDED_NODES 
  2. Then you read the lines of your data structure into it_expanded using the node keys
    • You need to save the Node Keys of the Tree in the it_data structure when you build it, so you can now find the corresponding line
    • The mt_outtab of the tree would also work, but its protected in the class and i dont know how to access it. Comment if you know how
  3. You do your refresh now
    • Your it_data contains the new data and the new nodekeys now. 
    • The l_it_expanded contains the old expanded data with the worthless node keys
  4. You can now read the new data itab using the real key tuple of your it_expanded
  5. Because you have the node keys saved inside the it_data after the read you kann append to a node key table to add all expanded
    • Also you are able to react on changes like missing lines 
  6. You can now use EXPAND_NODES with you node key table.
here is a code sample how i worked it out. It might be more difficult to read since we are using a framework between ALV Tree and our code.



      "Tabelle für Expandierte Knoten
      DATAL_WA_OUTLINEOLD TYPE TP_T_TREE_TAB.

........

Inside a function for e.g. Text updates

   "Speichern der Expandierten Knoten für Refresh
          CLEAR L_WA_OUTLINEOLD.
          PERFORM CUST_TREE_SAVE_EXPANDED CHANGING L_WA_OUTLINEOLD.

          "Texte über Lagernummer ermitteln
          PERFORM CUST_GET_TXTS_FOR_TRANSPORT USING C_WA_TREE_TAB-TKNUM.

          "LayoutRefresh und Laden der Expandierten Knoten
          PERFORM STD_REFRESH_SELECTION.
          PERFORM CUST_TREE_EXPAND_SAVED_NODES USING L_WA_OUTLINEOLD.



The important functions here are:

*&---------------------------------------------------------------------*
*&      Form  CUST_TREE_SAVE_EXPANDED
*&---------------------------------------------------------------------*
*       Ausgeklappte Knoten für den Refresh speichern
*       Das Problem ist, dass ein Refresh alle Knoten löscht und neu
*       anlegt aber die Schlüssel der Knoten einfach fortzählt.
*       Deshalb sind die gespeicherten Schlüssel unbrauchbar und
*       eine Verbindung muss über die Wertetupel des eigentlichen
*       Tabelleninhalte geschaffen werden um die Zeilen nach dem
*       neuaufbau wieder zu finden.
*----------------------------------------------------------------------*
*      <--C_IT_OUTLINEOLD  Tabelle mit den Realen ausgeklappten zeilen
*----------------------------------------------------------------------*
FORM CUST_TREE_SAVE_EXPANDED
          CHANGING C_IT_OUTLINEOLD TYPE TP_T_TREE_TAB.

  DATA:       L_IT_NODES      TYPE LVC_T_NKEY,
              L_WA_NODE       TYPE LVC_NKEY,
              L_WA_OUTLINEOLD TYPE TP_TREE_TAB.

  "Expandierte Knoten lesen
  CALL METHOD REF_TREE->GET_EXPANDED_NODES
    CHANGING
      CT_EXPANDED_NODES L_IT_NODES
    EXCEPTIONS
      CNTL_SYSTEM_ERROR 1
      DP_ERROR          2
      FAILED            3
      OTHERS            4.
  IF SY-SUBRC <> 0.
    MESSAGE ID SY-MSGID TYPE 'S' NUMBER SY-MSGNO
                       WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4
                         DISPLAY LIKE SY-MSGTY.
  ENDIF.

  "Knoten in Inbhaltstabelle Übersetzen
  LOOP AT L_IT_NODES INTO L_WA_NODE.
    REF_TREE->GET_OUTTAB_LINE(
      EXPORTING
        I_NODE_KEY     =   L_WA_NODE  " node key
      IMPORTING
        E_OUTTAB_LINE  L_WA_OUTLINEOLD
      EXCEPTIONS
        NODE_NOT_FOUND 1
        OTHERS         2
    ).

    IF SY-SUBRC <> 0.
      MESSAGE ID SY-MSGID TYPE 'S' NUMBER SY-MSGNO
                 WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4
                 DISPLAY LIKE SY-MSGTY.
    ENDIF.

    "Durch die Inhaltstabelle mit Wertetupeln wird der Bezug zu den
    "neuen Knoten hergestellt
    APPEND L_WA_OUTLINEOLD TO C_IT_OUTLINEOLD.

  ENDLOOP.


ENDFORM.                    " CUST_TREE_SAVE_EXPANDED
*&---------------------------------------------------------------------*
*&      Form  CUST_TREE_EXPAND_SAVED_NODES
*&---------------------------------------------------------------------*
*       Ausklappen der gespeicherten Tree Zeilen. Ausfühliche besch-
*       reibung des Problem unter CUST_TREE_SAVE_EXPANDED.
*----------------------------------------------------------------------*
*      -->F_IT_OUTLINEOLD  Zeilen zum Ausklappen
*----------------------------------------------------------------------*
FORM CUST_TREE_EXPAND_SAVED_NODES
              USING    F_IT_OUTLINEOLD TYPE TP_T_TREE_TAB.


  DATA:       L_IT_NODES      TYPE LVC_T_NKEY,
              L_WA_NODE       TYPE LVC_NKEY,
              L_WA_OUTLINEOLD TYPE TP_TREE_TAB,
              L_WA_TREETABNEW TYPE TP_TREE_TAB.

  "Inhaltstabelle lesen und die neuen entsprechenden Knoten ausklappen
  LOOP AT F_IT_OUTLINEOLD INTO L_WA_OUTLINEOLD.

    READ TABLE  IT_TREE_TAB
                INTO L_WA_TREETABNEW
                WITH KEY  TKNUM L_WA_OUTLINEOLD-TKNUM
                          VENUM L_WA_OUTLINEOLD-VENUM
                          EXIDV L_WA_OUTLINEOLD-EXIDV
                          LINETYPE L_WA_OUTLINEOLD-LINETYPE.

    IF SY-SUBRC 0.
      APPEND L_WA_TREETABNEW-NODE_KEY TO L_IT_NODES.
    ENDIF.

  ENDLOOP.

  CALL METHOD REF_TREE->EXPAND_NODES
    EXPORTING
      IT_NODE_KEY             L_IT_NODES
    EXCEPTIONS
      FAILED                  1
      CNTL_SYSTEM_ERROR       2
      ERROR_IN_NODE_KEY_TABLE 3
      DP_ERROR                4
      NODE_NOT_FOUND          5
      OTHERS                  6.
  IF SY-SUBRC <> 0.
    MESSAGE ID SY-MSGID TYPE 'S' NUMBER SY-MSGNO
                   WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4
                         DISPLAY LIKE SY-MSGTY.
  ENDIF.

  "Update der Darstellung
  REF_TREE->FRONTEND_UPDATE).

ENDFORM.                    " CUST_TREE_EXPAND_SAVED_NODES


Feel free to comment, especially for better solutions for this problem. I need to add, since the framework is in between, we are not able to use other refresh functions, but i've heard that there is a different solution where you don't use DELETE_ALL_NODES but i think any solutions using the keys might be faulty due to possible changes in the structure resulting in wrong node keys for a line.