Samples / Controls / sap.m

Tab Container - Multi-instance handling concept

Allows detail view / edit in sap.m.TabContainer after selecting items from table.

Class
z2ui5_cl_smpc_app_558
Repository
abap2UI5/samples-controls
Ports
sap.m.sample.TabContainerMHC
UI5 libraries
sap.m, sap.ui.core, sap.ui.layout
Lowest UI5 release
1.71
In the browser
Runs in the playground
Controls it builds
sap.m.Button, sap.m.Column, sap.m.ColumnListItem, sap.m.Input, sap.m.Label, sap.m.NavContainer, sap.m.ObjectAttribute, sap.m.ObjectHeader, sap.m.OverflowToolbar, sap.m.OverflowToolbarButton, sap.m.Page, sap.m.TabContainer, sap.m.TabContainerItem, sap.m.Table, sap.m.Text, sap.m.TextArea, sap.m.Toolbar, sap.m.ToolbarSpacer, sap.ui.core.mvc.View, sap.ui.layout.form.SimpleForm

The class

" @keywords tabcontainer tab container sap.m tabcontainermhc navcontainer overflowtoolbar toolbarspacer overflowtoolbarbutton column text columnlistitem
" @summary Allows detail view / edit in sap.m.TabContainer after selecting items from table.
" @origin sap.m.sample.TabContainerMHC - https://sdk.openui5.org/entity/sap.m.TabContainer/sample/sap.m.sample.TabContainerMHC (status: generated - machine-written, not yet reviewed)
CLASS z2ui5_cl_smpc_app_558 DEFINITION PUBLIC.

  PUBLIC SECTION.
    INTERFACES z2ui5_if_app.

    TYPES:
      BEGIN OF ty_s_product,
        productid    TYPE string,
        name         TYPE string,
        suppliername TYPE string,
        description  TYPE string,
        price        TYPE p LENGTH 14 DECIMALS 2,
        currencycode TYPE string,
        selected     TYPE abap_bool,
        " _oNewUnsavedItems: rows the add-new button created and nobody saved yet
        unsaved      TYPE abap_bool,
      END OF ty_s_product.
    TYPES ty_t_product TYPE STANDARD TABLE OF ty_s_product WITH EMPTY KEY.

    " one row per open tab - a COPY of the product, which is what makes Cancel a
    " pure discard (the original edits a deepExtend copy in its own JSONModel)
    TYPES:
      BEGIN OF ty_s_tab,
        productid    TYPE string,
        name         TYPE string,
        suppliername TYPE string,
        description  TYPE string,
        price        TYPE p LENGTH 14 DECIMALS 2,
        currencycode TYPE string,
        modified     TYPE abap_bool,
      END OF ty_s_tab.
    TYPES ty_t_tab TYPE STANDARD TABLE OF ty_s_tab WITH EMPTY KEY.

    DATA t_products     TYPE ty_t_product.
    DATA t_tabs         TYPE ty_t_tab.
    DATA open_visible   TYPE abap_bool.
    DATA edit_visible   TYPE abap_bool VALUE abap_true.
    DATA save_visible   TYPE abap_bool.
    DATA cancel_visible TYPE abap_bool.
    DATA add_name        TYPE string.
    DATA add_supplier    TYPE string.
    DATA add_price       TYPE p LENGTH 14 DECIMALS 2.
    DATA add_description TYPE string.

  PROTECTED SECTION.
    DATA client         TYPE REF TO z2ui5_if_client.
    DATA selected_tab   TYPE string.
    DATA pending_close  TYPE string.
    " _bEditMode of the add-item page
    DATA add_mode       TYPE abap_bool.
    DATA add_product_id TYPE string.
    DATA new_counter    TYPE i.

    " The page the LIVE navCon was last sent to, so a rebuilt view can be sent
    " there again (see view_display). Empty until something navigated, which is
    " the guard. PROTECTED, not PUBLIC: it is bookkeeping and not model data,
    " and only PUBLIC attributes are serialized into the view model - and not
    " PRIVATE, because the draft serialization walks the attributes with a
    " dynamic ASSIGN obj->(name) that cannot reach a PRIVATE one
    DATA nav_page TYPE string.

    METHODS view_display.
    METHODS buttons_state
      IMPORTING edit   TYPE abap_bool DEFAULT abap_false
                save   TYPE abap_bool DEFAULT abap_false
                cancel TYPE abap_bool DEFAULT abap_false.
    METHODS nav_to_table.
    METHODS nav_back.
    METHODS unsaved_reset IMPORTING productid TYPE string OPTIONAL.
    METHODS tab_close IMPORTING productid TYPE string.
    METHODS tab_save.
    METHODS on_event.
    METHODS model_init.

  PRIVATE SECTION.
ENDCLASS.


CLASS z2ui5_cl_smpc_app_558 IMPLEMENTATION.

  METHOD z2ui5_if_app~main.

    me->client = client.
    IF client->check_on_init( ).
      model_init( ).
      view_display( ).
    ELSEIF client->check_on_navigated( ).
      view_display( ).
    ELSEIF client->check_on_event( ).
      on_event( ).
    ENDIF.

  ENDMETHOD.


  METHOD view_display.

    DATA(view) = z2ui5_cl_ui5_view_builder=>factory( ).

    DATA(pages) = view->ele( n = `View` ns = `mvc`
        )->a( n = `height`     v = `100%`
        )->a( n = `xmlns`      v = `sap.m`
        )->a( n = `xmlns:mvc`  v = `sap.ui.core.mvc`
        )->a( n = `xmlns:form` v = `sap.ui.layout.form`

        )->ele( `NavContainer`
            )->a( n = `id` v = `navCon` ).

    DATA(table_page) = pages->ele( `Page`
        )->a( n = `id`    v = `table`
        )->a( n = `title` v = `Product List` ).

    table_page->ele( `Table`
        )->a( n = `id`              v = `idProductsTable`
        )->a( n = `mode`            v = `MultiSelect`
        )->a( n = `items`           v = client->_bind( t_products )
        " onInit attaches selectionChange to keep the footer button in sync
        )->a( n = `selectionChange` v = client->_event( `SELECTION_CHANGE` )

        )->ele( `headerToolbar`
            )->ele( `OverflowToolbar`
                )->tag( `ToolbarSpacer`
                )->tag( `OverflowToolbarButton`
                    )->a( n = `type`    v = `Transparent`
                    )->a( n = `icon`    v = `sap-icon://add`
                    )->a( n = `tooltip` v = `Add`
                    )->a( n = `press`   v = client->_event( `NEW_ITEM_ADD` )

            )->end(
        )->end(
        )->ele( `columns`
            )->ele( `Column`
                )->a( n = `width` v = `12em`

                )->tag( `Text`
                    )->a( n = `text` v = `Product`

            )->end(
            )->ele( `Column`
                )->a( n = `width` v = `12em`

                )->tag( `Text`
                    )->a( n = `text` v = `Supplier`

            )->end(
        )->end(
        )->ele( `items`
            )->ele( `ColumnListItem`
                " the original reads the selection with getSelectedContexts; the flag
                " is bound two-way here so the backend has it on every round trip
                )->a( n = `selected` v = `{SELECTED}`

                )->ele( `cells`
                    )->tag( `Text`
                        )->a( n = `text` v = `{NAME}`
                    )->tag( `Text`
                        )->a( n = `text` v = `{SUPPLIERNAME}`

                )->end(
            )->end(
        )->end(
    )->end( ).

    table_page->ele( `footer`
        )->ele( `Toolbar`
            )->tag( `ToolbarSpacer`
            )->tag( `Button`
                )->a( n = `id`      v = `idOpenSelected`
                )->a( n = `text`    v = `Open selected item(s)`
                )->a( n = `type`    v = `Emphasized`
                )->a( n = `visible` v = client->_bind( open_visible )
                )->a( n = `press`   v = client->_event( `OPEN_SELECTED` ) ).

    DATA(tab_page) = pages->ele( `Page`
        )->a( n = `id`             v = `tabContainerPage`
        )->a( n = `title`          v = `Tab Container`
        )->a( n = `showNavButton`  v = `true`
        )->a( n = `navButtonPress` v = client->_event( `NAV_BACK` ) ).

    " openSelectedItems builds the TabContainer in the controller and inserts it
    " into the page; here it is declared and its items are bound to the open tabs
    " sap.m.TabContainer has no default aggregation, so the item template sits in
    " an explicit items element next to the items binding
    DATA(tab_item) = tab_page->ele( `TabContainer`
        )->a( n = `id`                v = `idTabContainer`
        )->a( n = `showAddNewButton`  v = `true`
        )->a( n = `addNewButtonPress` v = client->_event( `TAB_ADD_NEW` )
        " _handleTabContainerItemClose opens with oEvent.preventDefault( ) and
        " closes the tab itself once the user has confirmed. check_prevent_default
        " IS that call: the control does not close the tab, the event still
        " reaches the backend, and tab_close( ) decides
        )->a( n = `itemClose`         v = client->_event( val    = `TAB_CLOSE`
                                                          arg    = `${$parameters>/item}.getKey()`
                                                          s_ctrl = VALUE #( check_prevent_default = abap_true ) )
        )->a( n = `itemSelect`        v = client->_event( val = `TAB_SELECT` arg = `${$parameters>/item}.getKey()` )
        )->a( n = `items`             v = client->_bind( t_tabs )

        )->ele( `items`
            )->ele( `TabContainerItem`
                )->a( n = `key`      v = `{PRODUCTID}`
                )->a( n = `name`     v = `{NAME}`
                )->a( n = `modified` v = `{MODIFIED}` ).

    DATA(tab_content) = tab_item->ele( `content` ).

    " the Display fragment - what a tab shows while it is not being edited
    tab_content->ele( `ObjectHeader`
        )->a( n = `visible`    v = |\{= !$\{MODIFIED\} \}|
        )->a( n = `title`      v = `{NAME}`
        )->a( n = `number`     v = |\{ parts:[\{path:'PRICE'\},\{path:'CURRENCYCODE'\}], type:'sap.ui.model.type.Currency', formatOptions:\{showMeasure:false\} \}|
        )->a( n = `numberUnit` v = `{CURRENCYCODE}`

        )->ele( `attributes`
            )->tag( `ObjectAttribute`
                )->a( n = `text` v = `{SUPPLIERNAME}`
            )->tag( `ObjectAttribute`
                )->a( n = `text` v = `{DESCRIPTION}`

        )->end(
    )->end( ).

    " the Edit fragment - the tab edits its OWN copy of the row, which is what
    " makes Cancel a pure discard
    tab_content->ele( n = `SimpleForm` ns = `form`
        )->a( n = `visible`  v = |\{= $\{MODIFIED\} \}|
        )->a( n = `editable` v = `true`
        )->a( n = `layout`   v = `ResponsiveGridLayout`

        )->tag( `Label`
            )->a( n = `text` v = `Name`
        )->tag( `Input`
            )->a( n = `value` v = `{NAME}`
            )->a( n = `type`  v = `Text`
        )->tag( `Label`
            )->a( n = `text` v = `Supplier`
        )->tag( `Input`
            )->a( n = `value` v = `{SUPPLIERNAME}`
            )->a( n = `type`  v = `Text`
        )->tag( `Label`
            )->a( n = `text` v = `Price`
        )->tag( `Input`
            )->a( n = `value` v = `{PRICE}`
            )->a( n = `type`  v = `Number`
        )->tag( `Label`
            )->a( n = `text` v = `Description`
        )->tag( `TextArea`
            )->a( n = `value` v = `{DESCRIPTION}` ).

    DATA(add_page) = pages->ele( `Page`
        )->a( n = `id`             v = `addItemPage`
        )->a( n = `showNavButton`  v = `true`
        )->a( n = `navButtonPress` v = client->_event( `NAV_BACK` ) ).

    " handleNewItemAdd loads the same Edit fragment into the add page, over a fresh
    " JSONModel; here the add page's form binds the four add_* fields
    add_page->ele( n = `SimpleForm` ns = `form`
        )->a( n = `id`       v = `myForm`
        )->a( n = `editable` v = `true`
        )->a( n = `layout`   v = `ResponsiveGridLayout`

        )->tag( `Label`
            )->a( n = `text` v = `Name`
        )->tag( `Input`
            )->a( n = `value` v = client->_bind( add_name )
            )->a( n = `type`  v = `Text`
        )->tag( `Label`
            )->a( n = `text` v = `Supplier`
        )->tag( `Input`
            )->a( n = `value` v = client->_bind( add_supplier )
            )->a( n = `type`  v = `Text`
        )->tag( `Label`
            )->a( n = `text` v = `Price`
        )->tag( `Input`
            )->a( n = `value` v = client->_bind( add_price )
            )->a( n = `type`  v = `Number`
        )->tag( `Label`
            )->a( n = `text` v = `Description`
        )->tag( `TextArea`
            )->a( n = `value` v = client->_bind( add_description ) ).

    add_page->ele( `footer`
        )->ele( `Toolbar`
            )->tag( `ToolbarSpacer`
            )->tag( `Button`
                )->a( n = `text`  v = `Save`
                )->a( n = `type`  v = `Emphasized`
                )->a( n = `press` v = client->_event( `NEW_ITEM_SAVE` )
            )->tag( `Button`
                )->a( n = `text`  v = `Cancel`
                )->a( n = `type`  v = `Default`
                )->a( n = `press` v = client->_event( `NEW_ITEM_CANCEL` ) ).

    tab_page->ele( `footer`
        )->ele( `Toolbar`
            )->tag( `ToolbarSpacer`
            )->tag( `Button`
                )->a( n = `id`      v = `idEditItem`
                )->a( n = `text`    v = `Edit`
                )->a( n = `type`    v = `Default`
                )->a( n = `visible` v = client->_bind( edit_visible )
                )->a( n = `press`   v = client->_event( `TAB_EDIT` )
            )->tag( `Button`
                )->a( n = `id`      v = `idSaveItem`
                )->a( n = `text`    v = `Save`
                )->a( n = `type`    v = `Emphasized`
                )->a( n = `visible` v = client->_bind( save_visible )
                )->a( n = `press`   v = client->_event( `TAB_SAVE` )
            )->tag( `Button`
                )->a( n = `id`      v = `idCancel`
                )->a( n = `text`    v = `Cancel`
                )->a( n = `type`    v = `Default`
                )->a( n = `visible` v = client->_bind( cancel_visible )
                )->a( n = `press`   v = client->_event( `TAB_CANCEL` ) ).

    client->view_display( view->stringify( ) ).

    " The NavContainer's position is live control state: view_display( )
    " destroys the MAIN slot and XMLView.create builds a fresh tree, so navCon
    " comes back on its FIRST page - the table, this NavContainer declaring no
    " initialPage - while selected_tab, save_visible and cancel_visible survive
    " as class state. Four of the five branches that call view_display( ) are
    " reachable only FROM tabContainerPage (TAB_CANCEL, TAB_CLOSE,
    " CLOSE_TAB_CLOSED, TAB_ADD_NEW), so pressing + on the tab bar created the
    " tab and dropped the user on the product list while the buttons claimed an
    " open tab in edit mode. Re-issued from the LAST-issued target rather than
    " re-derived, so the branches that DO want the table (nav_to_table, the
    " tab_close redirect when the last tab goes) park `table` and are skipped
    " here by the same guard. The app-000 idiom
    IF nav_page IS NOT INITIAL AND nav_page <> `table`.
      client->follow_up_action( val   = client->cs_event-control_by_id
                                t_arg = VALUE #( ( `navCon` ) ( `to` ) ( nav_page ) ) ).
    ENDIF.

    " onInit: oModel.setSizeLimit(200) - the collection is 123 rows and the
    " JSONModel caps a bound aggregation at 100, so without this the table
    " stops 23 rows short (the app-252 / app-444 idiom)
    client->follow_up_action( val   = client->cs_event-set_size_limit
                              t_arg = VALUE #( ( `200` ) ( client->cs_view-main ) ) ).

  ENDMETHOD.


  METHOD buttons_state.

    edit_visible   = edit.
    save_visible   = save.
    cancel_visible = cancel.

  ENDMETHOD.


  METHOD nav_to_table.

    " fnGoBackToTablePage: back to the table page, and the footer button follows
    " the selection that is left
    client->follow_up_action( val   = client->cs_event-control_by_id
                              t_arg = VALUE #( ( `navCon` ) ( `back` ) ) ).
    nav_page = `table`.
    open_visible = xsdbool( line_exists( t_products[ selected = abap_true ] ) ).

  ENDMETHOD.


  METHOD nav_back.

    " fnNavBackButton: leaving a page with unsaved edits asks first
    DATA(modified_names) = ``.
    LOOP AT t_tabs INTO DATA(tab) WHERE modified = abap_true.
      modified_names = modified_names && |\n| && tab-name.
    ENDLOOP.

    IF add_mode = abap_true OR modified_names IS NOT INITIAL.
      client->message_box_display(
          text         = |Your changes to the following tabs will be lost when you leave the page: \n{ modified_names }|
          type         = `warning`
          title        = `Warning`
          actions      = VALUE #( ( `Leave Page` ) ( `CANCEL` ) )
          initialfocus = `CANCEL`
          onclose      = `LEAVE_CLOSED` ).
      RETURN.
    ENDIF.

    nav_to_table( ).

  ENDMETHOD.


  METHOD unsaved_reset.

    " _resetUnsavedItems: drop the rows the add-new button created and nobody saved
    IF productid IS INITIAL.
      DELETE t_products WHERE unsaved = abap_true.
      RETURN.
    ENDIF.
    DATA(del_id) = productid.
    DELETE t_products WHERE unsaved = abap_true AND productid = del_id.

  ENDMETHOD.


  METHOD tab_close.

    DATA(del_id) = productid.
    DELETE t_tabs WHERE productid = del_id.

    " un-check the row in the table, exactly as _closeItemInTabContainer does
    " IS ASSIGNED, not sy-subrc: a SUCCESSFUL dynamic ASSIGN does not reset
    " sy-subrc on every release (abap2UI5 #1937)
    ASSIGN t_products[ productid = del_id ] TO FIELD-SYMBOL(<product>).
    IF <product> IS ASSIGNED.
      <product>-selected = abap_false.
    ENDIF.

    unsaved_reset( del_id ).

    " redirect to the table if no tab is left
    IF t_tabs IS INITIAL.
      nav_to_table( ).
    ENDIF.

  ENDMETHOD.


  METHOD tab_save.

    " handleTabContainerSaveItem: the tab's copy is written back to the product
    ASSIGN t_tabs[ productid = selected_tab ] TO FIELD-SYMBOL(<saved_tab>).
    IF <saved_tab> IS NOT ASSIGNED.
      RETURN.
    ENDIF.
    <saved_tab>-modified = abap_false.

    ASSIGN t_products[ productid = selected_tab ] TO FIELD-SYMBOL(<target>).
    IF <target> IS ASSIGNED.
      <target>-name         = <saved_tab>-name.
      <target>-suppliername = <saved_tab>-suppliername.
      <target>-description  = <saved_tab>-description.
      <target>-price        = <saved_tab>-price.
      <target>-currencycode = <saved_tab>-currencycode.
      " the row is a real product now, not an unsaved one
      <target>-unsaved      = abap_false.
    ENDIF.

    buttons_state( edit = abap_true ).

  ENDMETHOD.


  METHOD on_event.

    CASE client->get_event( ).

      WHEN `SELECTION_CHANGE`.
        open_visible = xsdbool( line_exists( t_products[ selected = abap_true ] ) ).

      WHEN `OPEN_SELECTED`.
        " openSelectedItems: one tab per selected row, filtered by ProductId
        t_tabs = VALUE #( ).
        LOOP AT t_products INTO DATA(product) WHERE selected = abap_true.
          APPEND CORRESPONDING #( product ) TO t_tabs.
        ENDLOOP.
        selected_tab = VALUE #( t_tabs[ 1 ]-productid OPTIONAL ).
        buttons_state( edit = abap_true ).
        nav_page = `tabContainerPage`.
        client->follow_up_action( val   = client->cs_event-control_by_id
                                  t_arg = VALUE #( ( `navCon` ) ( `to` ) ( nav_page ) ) ).

      WHEN `TAB_SELECT`.
        selected_tab = client->get_event_arg( ).
        " _handleTabContainerItemSelect: the buttons follow the tab's modified flag
        DATA(is_modified) = xsdbool( line_exists( t_tabs[ productid = selected_tab modified = abap_true ] ) ).
        buttons_state( edit = xsdbool( is_modified = abap_false ) save = is_modified cancel = is_modified ).

      WHEN `TAB_EDIT`.
        " handleTabContainerEditItem: the tab goes into edit mode over its own copy
        ASSIGN t_tabs[ productid = selected_tab ] TO FIELD-SYMBOL(<tab>).
        IF <tab> IS NOT ASSIGNED.
          RETURN.
        ENDIF.
        <tab>-modified = abap_true.
        buttons_state( save = abap_true cancel = abap_true ).

      WHEN `TAB_SAVE`.
        tab_save( ).

      WHEN `TAB_CANCEL`.
        " handleTabContainerCancelUpdate: a never-saved row disappears with its tab,
        " an existing one falls back to the stored product
        buttons_state( edit = abap_true ).
        IF line_exists( t_products[ productid = selected_tab unsaved = abap_true ] ).
          tab_close( selected_tab ).
        ELSE.
          ASSIGN t_tabs[ productid = selected_tab ] TO FIELD-SYMBOL(<reset_tab>).
          IF <reset_tab> IS ASSIGNED.
            <reset_tab> = CORRESPONDING #( t_products[ productid = selected_tab ] ).
          ENDIF.
        ENDIF.
        view_display( ).

      WHEN `TAB_CLOSE`.
        pending_close = client->get_event_arg( ).
        " _handleTabContainerItemClose: a modified tab asks before it goes
        IF line_exists( t_tabs[ productid = pending_close modified = abap_true ] ).
          client->message_box_display( text         = `Your changes will be lost when you close this tab`
                                       type         = `warning`
                                       title        = `Warning`
                                       actions      = VALUE #( ( `Close Tab` ) ( `CANCEL` ) )
                                       initialfocus = `CANCEL`
                                       onclose      = `CLOSE_TAB_CLOSED` ).
        ELSE.
          tab_close( pending_close ).
        ENDIF.
        " the close was vetoed on the wire, so the tab is still there either way:
        " a confirmed close removes its row and this display drops it, a
        " cancelled one leaves the row and the tab simply stays
        view_display( ).

      WHEN `CLOSE_TAB_CLOSED`.
        IF client->get_event_arg( ) <> `CANCEL`.
          tab_close( pending_close ).
        ENDIF.
        view_display( ).

      WHEN `TAB_ADD_NEW`.
        " _handleTabContainerAddNewButtonPress: a blank product joins the collection,
        " gets selected in the table, opens as a tab and starts in edit mode
        new_counter = new_counter + 1.
        DATA(new_id) = |ProductId-{ new_counter }|.
        APPEND VALUE #( productid    = new_id
                        currencycode = `EUR`
                        selected     = abap_true
                        unsaved      = abap_true ) TO t_products.
        APPEND VALUE #( productid = new_id currencycode = `EUR` modified = abap_true ) TO t_tabs.
        selected_tab = new_id.
        buttons_state( save = abap_true cancel = abap_true ).
        view_display( ).

      WHEN `NEW_ITEM_ADD`.
        " handleNewItemAdd: a fresh edit model on the add page
        new_counter = new_counter + 1.
        add_product_id = |ProductId-{ new_counter }|.
        add_name = VALUE #( ).
        add_supplier = VALUE #( ).
        add_description = VALUE #( ).
        add_price = 0.
        add_mode = abap_true.
        nav_page = `addItemPage`.
        client->follow_up_action( val   = client->cs_event-control_by_id
                                  t_arg = VALUE #( ( `navCon` ) ( `to` ) ( nav_page ) ) ).

      WHEN `NEW_ITEM_SAVE`.
        " handleNewItemSave: the form's data joins the collection
        APPEND VALUE #( productid    = add_product_id
                        name         = add_name
                        suppliername = add_supplier
                        description  = add_description
                        price        = add_price
                        currencycode = `EUR` ) TO t_products.
        add_mode = abap_false.
        nav_to_table( ).

      WHEN `NEW_ITEM_CANCEL`.
        add_mode = abap_false.
        nav_to_table( ).

      WHEN `NAV_BACK`.
        nav_back( ).

      WHEN `LEAVE_CLOSED`.
        " the confirmation's non-cancel action: leave the page and drop every row
        " the add-new button created and nobody saved
        IF client->get_event_arg( ) <> `CANCEL`.
          add_mode = abap_false.
          nav_to_table( ).
          unsaved_reset( ).
          " a tab whose product is gone goes with it.
          "
          " Built rather than deleted from: `DELETE t_tabs INDEX sy-tabix`
          " inside `LOOP AT t_tabs` deletes by the LOOP'S OWN cursor, so the
          " table shortens under the walk - the row after a deleted one is
          " skipped, and deleting the last row leaves sy-tabix past the end
          " (TABLE_INVALID_INDEX). Same defect the ports 352/354/298/377
          " carried and the same fix.
          DATA(keep) = t_tabs.
          t_tabs = VALUE #( ).
          LOOP AT keep REFERENCE INTO DATA(tab).
            IF line_exists( t_products[ productid = tab->productid ] ).
              INSERT tab->* INTO TABLE t_tabs.
            ENDIF.
          ENDLOOP.
          view_display( ).
        ENDIF.

    ENDCASE.

  ENDMETHOD.


  METHOD model_init.

    " the full mock /ProductCollection (sap/ui/demo/mock/products.json), all 123
    " rows - onInit raises the model size limit to 200 so the table shows them all
    t_products = VALUE #(
      ( productid = `HT-1000` name = `Notebook Basic 15`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `956`
        description = `Notebook Basic 15 with 2,80 GHz quad core, 15" LCD, 4 GB DDR3 RAM, 500 GB Hard Disc, Windows 8 Pro` )
      ( productid = `HT-1001` name = `Notebook Basic 17`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `1249`
        description = `Notebook Basic 17 with 2,80 GHz quad core, 17" LCD, 4 GB DDR3 RAM, 500 GB Hard Disc, Windows 8 Pro` )
      ( productid = `HT-1002` name = `Notebook Basic 18`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `1570`
        description = `Notebook Basic 18 with 2,80 GHz quad core, 18" LCD, 8 GB DDR3 RAM, 1000 GB Hard Disc, Windows 8 Pro` )
      ( productid = `HT-1003` name = `Notebook Basic 19`
        suppliername = `Smartcards` currencycode = `EUR` price = `1650`
        description = `Notebook Basic 19 with 2,80 GHz quad core, 19" LCD, 8 GB DDR3 RAM, 1000 GB Hard Disc, Windows 8 Pro` )
      ( productid = `HT-1007` name = `ITelO Vault`
        suppliername = `Technocom` currencycode = `EUR` price = `299`
        description = `Digital Organizer with State-of-the-Art Storage Encryption` )
      ( productid = `HT-1010` name = `Notebook Professional 15`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `1999`
        description = `Notebook Professional 15 with 2,80 GHz quad core, 15" Multitouch LCD, 8 GB DDR3 RAM, 500 GB SSD - DVD-Writer (DVD-R/+R/-RW/-RAM),Windows 8 Pro` )
      ( productid = `HT-1011` name = `Notebook Professional 17`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `2299`
        description = `Notebook Professional 17 with 2,80 GHz quad core, 17" Multitouch LCD, 8 GB DDR3 RAM, 500 GB SSD - DVD-Writer (DVD-R/+R/-RW/-RAM),Windows 8 Pro` )
      ( productid = `HT-1020` name = `ITelO Vault Net`
        suppliername = `Technocom` currencycode = `EUR` price = `459`
        description = `Digital Organizer with State-of-the-Art Encryption for Storage and Network Communications` )
      ( productid = `HT-1021` name = `ITelO Vault SAT`
        suppliername = `Technocom` currencycode = `EUR` price = `149`
        description = `Digital Organizer with State-of-the-Art Encryption for Storage and Secure Stellite Link` )
      ( productid = `HT-1022` name = `Comfort Easy`
        suppliername = `Technocom` currencycode = `EUR` price = `1679`
        description = `32 GB Digital Assistant with high-resolution color screen` )
      ( productid = `HT-1023` name = `Comfort Senior`
        suppliername = `Technocom` currencycode = `EUR` price = `512`
        description = `64 GB Digital Assistant with high-resolution color screen and synthesized voice output` )
      ( productid = `HT-1030` name = `Ergo Screen E-I`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `230`
        description = `Optimum Hi-Resolution max. 1920 x 1080 @ 85Hz, Dot Pitch: 0.27mm` )
      ( productid = `HT-1031` name = `Ergo Screen E-II`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `285`
        description = `Optimum Hi-Resolution max. 1920 x 1200 @ 85Hz, Dot Pitch: 0.26mm` )
      ( productid = `HT-1032` name = `Ergo Screen E-III`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `345`
        description = `Optimum Hi-Resolution max. 2560 x 1440 @ 85Hz, Dot Pitch: 0.25mm` )
      ( productid = `HT-1035` name = `Flat Basic`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `399`
        description = `Optimum Hi-Resolution max. 1600 x 1200 @ 85Hz, Dot Pitch: 0.24mm` )
      ( productid = `HT-1036` name = `Flat Future`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `430`
        description = `Optimum Hi-Resolution max. 2048 x 1080 @ 85Hz, Dot Pitch: 0.26mm` )
      ( productid = `HT-1037` name = `Flat XL`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `1230`
        description = `Optimum Hi-Resolution max. 2016 x 1512 @ 85Hz, Dot Pitch: 0.24mm` )
      ( productid = `HT-1040` name = `Laser Professional Eco`
        suppliername = `Alpha Printers` currencycode = `EUR` price = `830`
        description = `Print 2400 dpi image quality color documents at speeds of up to 32 ppm (color) or 36 ppm (monochrome), letter/A4. Powerful 500 MHz processor, 512MB of memory` )
      ( productid = `HT-1041` name = `Laser Basic`
        suppliername = `Alpha Printers` currencycode = `EUR` price = `490`
        description = `Up to 22 ppm color or 24 ppm monochrome A4/letter, powerful 500 MHz processor and 128MB of memory` )
      ( productid = `HT-1042` name = `Laser Allround`
        suppliername = `Alpha Printers` currencycode = `EUR` price = `349`
        description = `Print up to 25 ppm letter and 24 ppm A4 color or monochrome, with Available first-page-out-time of less than 13 seconds for monochrome and less than 15 seconds for color` )
      ( productid = `HT-1050` name = `Ultra Jet Super Color`
        suppliername = `Alpha Printers` currencycode = `EUR` price = `139`
        description = `4800 dpi x 1200 dpi - up to 35 ppm (mono) / up to 34 ppm (color) - capacity: 250 sheets - Hi-Speed USB, Ethernet` )
      ( productid = `HT-1051` name = `Ultra Jet Mobile`
        suppliername = `Printer for All` currencycode = `EUR` price = `99`
        description = `1000 dpi x 1000 dpi - up to 35 ppm (mono) / up to 34 ppm (color) - capacity: 250 sheets - Hi-Speed USB - excellent dimensions for the small office` )
      ( productid = `HT-1052` name = `Ultra Jet Super Highspeed`
        suppliername = `Printer for All` currencycode = `EUR` price = `170`
        description = `4800 dpi x 1200 dpi - up to 35 ppm (mono) / up to 34 ppm (color) - capacity: 250 sheets - Hi-Speed USB2.0, Ethernet` )
      ( productid = `HT-1055` name = `Multi Print`
        suppliername = `Printer for All` currencycode = `EUR` price = `99`
        description = `1000 dpi x 1000 dpi - up to 16 ppm (mono) / up to 15 ppm (color)- capacity 80 sheets - scanner (216 x 297 mm, 1200dpi x 2400dpi)` )
      ( productid = `HT-1056` name = `Multi Color`
        suppliername = `Printer for All` currencycode = `EUR` price = `119`
        description = `1200 dpi x 1200 dpi - up to 25 ppm (mono) / up to 24 ppm (color)- capacity 80 sheets - scanner (216 x 297 mm, 2400dpi x 4800dpi, high resolution)` )
      ( productid = `HT-1060` name = `Cordless Mouse`
        suppliername = `Oxynum` currencycode = `EUR` price = `9`
        description = `Cordless Optical USB Mice, Laptop, Color: Black, Plug&Play` )
      ( productid = `HT-1061` name = `Speed Mouse`
        suppliername = `Oxynum` currencycode = `EUR` price = `7`
        description = `Optical USB, PS/2 Mouse, Color: Blue, 3-button-functionality (incl. Scroll wheel)` )
      ( productid = `HT-1062` name = `Track Mouse`
        suppliername = `Oxynum` currencycode = `EUR` price = `11`
        description = `Optical USB Mouse, Color: Red, 5-button-functionality(incl. Scroll wheel), Plug&Play` )
      ( productid = `HT-1063` name = `Ergonomic Keyboard`
        suppliername = `Oxynum` currencycode = `EUR` price = `14`
        description = `Ergonomic USB Keyboard for Desktop, Plug&Play` )
      ( productid = `HT-1064` name = `Internet Keyboard`
        suppliername = `Oxynum` currencycode = `EUR` price = `16`
        description = `Corded Keyboard with special keys for Internet Usability, USB` )
      ( productid = `HT-1065` name = `Media Keyboard`
        suppliername = `Oxynum` currencycode = `EUR` price = `26`
        description = `Corded Ergonomic Keyboard with special keys for Media Usability, USB` )
      ( productid = `HT-1066` name = `Mousepad`
        suppliername = `Oxynum` currencycode = `EUR` price = `6.99`
        description = `Nice mouse pad with ITelO Logo` )
      ( productid = `HT-1067` name = `Ergo Mousepad`
        suppliername = `Oxynum` currencycode = `EUR` price = `8.99`
        description = `Ergonomic mouse pad with ITelO Logo` )
      ( productid = `HT-1068` name = `Designer Mousepad`
        suppliername = `Fasttech` currencycode = `EUR` price = `12.99`
        description = `ITelO Mousepad Special Edition` )
      ( productid = `HT-1069` name = `Universal card reader`
        suppliername = `Fasttech` currencycode = `EUR` price = `14`
        description = `Universal card reader` )
      ( productid = `HT-1070` name = `Proctra X`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `70.9`
        description = `Proctra X: PCI-E GDDR5 3072MB` )
      ( productid = `HT-1071` name = `Gladiator MX`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `81.7`
        description = `Gladiator XLN: PCI-E GDDR5 3072MB DVI Out, TV Out low-noise` )
      ( productid = `HT-1072` name = `Hurricane GX`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `101.2`
        description = `Hurricane GX: PCI-E 691 GFLOPS game-optimized` )
      ( productid = `HT-1073` name = `Hurricane GX/LN`
        suppliername = `Smartcards` currencycode = `EUR` price = `139.99`
        description = `Hurricane GX/LN: PCI-E 691 GFLOPS game-optimized, low-noise.` )
      ( productid = `HT-1080` name = `Photo Scan`
        suppliername = `Printer for All` currencycode = `EUR` price = `129`
        description = `Flatbed scanner - 9.600 × 9.600 dpi - 216 x 297 mm - Hi-Speed USB - Bluetooth` )
      ( productid = `HT-1081` name = `Power Scan`
        suppliername = `Printer for All` currencycode = `EUR` price = `89`
        description = `Flatbed scanner - 9.600 × 9.600 dpi - 216 x 297 mm - SCSI for backward compatibility` )
      ( productid = `HT-1082` name = `Jet Scan Professional`
        suppliername = `Printer for All` currencycode = `EUR` price = `169`
        description = `Flatbed scanner - Letter - 2400 dpi x 2400 dpi - 216 x 297 mm - add-on module` )
      ( productid = `HT-1083` name = `Jet Scan Professional`
        suppliername = `Printer for All` currencycode = `EUR` price = `189`
        description = `Flatbed scanner - A4 - 2400 dpi x 2400 dpi - 216 x 297 mm - add-on module` )
      ( productid = `HT-1085` name = `Copymaster`
        suppliername = `Alpha Printers` currencycode = `EUR` price = `1499`
        description = `Copymaster` )
      ( productid = `HT-1090` name = `Surround Sound`
        suppliername = `Speaker Experts` currencycode = `EUR` price = `39`
        description = `PC multimedia speakers - 5 Watt (Total)` )
      ( productid = `HT-1091` name = `Blaster Extreme`
        suppliername = `Speaker Experts` currencycode = `EUR` price = `26`
        description = `PC multimedia speakers - 10 Watt (Total) - 2-way` )
      ( productid = `HT-1092` name = `Sound Booster`
        suppliername = `Speaker Experts` currencycode = `EUR` price = `45`
        description = `PC multimedia speakers - optimized for Blutooth/A2DP` )
      ( productid = `HT-1095` name = `Lovely Sound 5.1 Wireless`
        suppliername = `Fasttech` currencycode = `EUR` price = `49`
        description = `5.1 Headset, 40 Hz-20 kHz, Wireless` )
      ( productid = `HT-1096` name = `Lovely Sound 5.1`
        suppliername = `Fasttech` currencycode = `EUR` price = `39`
        description = `5.1 Headset, 40 Hz-20 kHz, 3m cable` )
      ( productid = `HT-1097` name = `Lovely Sound Stereo`
        suppliername = `Fasttech` currencycode = `EUR` price = `29`
        description = `5.1 Headset, 40 Hz-20 kHz, 1m cable` )
      ( productid = `HT-1100` name = `Smart Office`
        suppliername = `Technocom` currencycode = `EUR` price = `89.9`
        description = `Complete package, 1 User, Office Applications (word processing, spreadsheet, presentations)` )
      ( productid = `HT-1101` name = `Smart Design`
        suppliername = `Technocom` currencycode = `EUR` price = `79.9`
        description = `Complete package, 1 User, Image editing, processing` )
      ( productid = `HT-1102` name = `Smart Network`
        suppliername = `Technocom` currencycode = `EUR` price = `69`
        description = `Complete package, 1 User, Network Software Utilities, Useful Applications and Documentation` )
      ( productid = `HT-1103` name = `Smart Multimedia`
        suppliername = `Technocom` currencycode = `EUR` price = `77`
        description = `Complete package, 1 User, different Multimedia applications, playing music, watching DVDs, only with this Smart package` )
      ( productid = `HT-1104` name = `Smart Games`
        suppliername = `Technocom` currencycode = `EUR` price = `55`
        description = `Complete package, 1 User, various games for amusement, logic, action, jump&run` )
      ( productid = `HT-1105` name = `Smart Internet Antivirus`
        suppliername = `Brainsoft` currencycode = `EUR` price = `29`
        description = `Complete package, 1 User, highly recommended for internet users as anti-virus protection` )
      ( productid = `HT-1106` name = `Smart Firewall`
        suppliername = `Brainsoft` currencycode = `EUR` price = `34`
        description = `Complete package, 1 User, recommended for internet users, protect your PC against cyber-crime` )
      ( productid = `HT-1107` name = `Smart Money`
        suppliername = `Brainsoft` currencycode = `EUR` price = `29.9`
        description = `Complete package, 1 User, bring your money in your mind, see what you have and what you want` )
      ( productid = `HT-1110` name = `PC Lock`
        suppliername = `Red Point Stores` currencycode = `EUR` price = `8.9`
        description = `Robust 3m anti-burglary protection for your laptop computer` )
      ( productid = `HT-1111` name = `Notebook Lock`
        suppliername = `Red Point Stores` currencycode = `EUR` price = `6.9`
        description = `Robust 1m anti-burglary protection for your desktop computer` )
      ( productid = `HT-1112` name = `Web cam reality`
        suppliername = `Red Point Stores` currencycode = `EUR` price = `39`
        description = `Color webcam, color, High-Speed USB` )
      ( productid = `HT-1113` name = `Screen clean`
        suppliername = `Red Point Stores` currencycode = `EUR` price = `2.3`
        description = `10 separately packed screen wipes` )
      ( productid = `HT-1114` name = `Fabric bag professional`
        suppliername = `Red Point Stores` currencycode = `EUR` price = `31`
        description = `Notebook bag, plenty of room for stationery and writing materials` )
      ( productid = `HT-1115` name = `Wireless DSL Router`
        suppliername = `Red Point Stores` currencycode = `EUR` price = `49`
        description = `Wireless DSL Router (available in blue, black and silver)` )
      ( productid = `HT-1116` name = `Wireless DSL Router / Repeater`
        suppliername = `Red Point Stores` currencycode = `EUR` price = `59`
        description = `Wireless DSL Router / Repeater (available in blue, black and silver)` )
      ( productid = `HT-1117` name = `Wireless DSL Router / Repeater and Print Server`
        suppliername = `Technocom` currencycode = `EUR` price = `69`
        description = `Wireless DSL Router / Repeater and Print Server (available in blue, black and silver)` )
      ( productid = `HT-1118` name = `USB Stick`
        suppliername = `Technocom` currencycode = `EUR` price = `35`
        description = `USB 2.0 High-Speed 64 GB` )
      ( productid = `HT-1119` name = `Travel Adapter`
        suppliername = `Titanium` currencycode = `EUR` price = `79`
        description = `Universal Travel Adapter` )
      ( productid = `HT-1120` name = `Cordless Bluetooth Keyboard, english international`
        suppliername = `Technocom` currencycode = `EUR` price = `29`
        description = `Cordless Bluetooth Keyboard with English keys` )
      ( productid = `HT-1137` name = `Flat XXL`
        suppliername = `Technocom` currencycode = `EUR` price = `1430`
        description = `Optimum Hi-Resolution max. 2048 × 1536 @ 85Hz, Dot Pitch: 0.24mm` )
      ( productid = `HT-1138` name = `Pocket Mouse`
        suppliername = `Technocom` currencycode = `EUR` price = `23`
        description = `Portable pocket Mouse with retracting cord` )
      ( productid = `HT-1210` name = `PC Power Station`
        suppliername = `Technocom` currencycode = `EUR` price = `2399`
        description = `PC Power Station with 3,4 Ghz quad-core, 32 GB DDR3 SDRAM, feels like Available PC, Windows 8 Pro` )
      ( productid = `HT-1251` name = `Astro Laptop 1516`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `989`
        description = `Flexible Laptop with 2,5 GHz Quad Core, 15" HD TN, 16 GB DDR SDRAM, 256 GB SSD, Windows 10 Pro` )
      ( productid = `HT-1252` name = `Astro Phone 6`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `649`
        description = `6 inch 1280x800 HD display (216 ppi), Quad-core processor, 8 GB internal storage (actual formatted capacity will be less), 3050 mAh battery (Up to 8 hours of active use), grey or black` )
      ( productid = `HT-1253` name = `Benda Laptop 1408`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `976`
        description = `Flexible Laptop with 2,5 GHz Dual Core, 14" HD+ TN, 8 GB DDR SDRAM, 324 GB SSD, Windows 10 Pro` )
      ( productid = `HT-1254` name = `Bending Screen 21HD`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `250`
        description = `Optimum Hi-Resolution Widescreen max. 1920 x 1080 @ 85Hz, Dot Pitch: 0.27mm, HDMI, Discontinued-Sub` )
      ( productid = `HT-1255` name = `Broad Screen 22HD`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `270`
        description = `Optimum Hi-Resolution Widescreen max. 2048 x 1080 @ 85Hz, Dot Pitch: 0.27mm, HDMI, Discontinued-Sub` )
      ( productid = `HT-1256` name = `Cerdik Phone 7`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `549`
        description = `7 inch 1280x800 HD display (216 ppi), Quad-core processor, 16 GB internal storage (actual formatted capacity will be less), 4325 mAh battery (Up to 8 hours of active use), white or black` )
      ( productid = `HT-1257` name = `Cepat Tablet 10.5`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `549`
        description = `10.5-inch Multitouch HD Screen (1280 x 800), 16GB Internal Memory, Wireless N Wi-Fi; Bluetooth, GPS Enabled, 1GHz Dual-Core Processor` )
      ( productid = `HT-1258` name = `Cepat Tablet 8`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `529`
        description = `8-inch Multitouch HD Screen (2000 x 1500) 32GB Internal Memory, Wireless N Wi-Fi, Bluetooth, GPS Enabled, 1.5 GHz Quad-Core Processor` )
      ( productid = `HT-1500` name = `Server Basic`
        suppliername = `Technocom` currencycode = `EUR` price = `5000`
        description = `Dual socket, quad-core processing server with 1333 MHz Front Side Bus with 10Gb connectivity` )
      ( productid = `HT-1501` name = `Server Professional`
        suppliername = `Technocom` currencycode = `EUR` price = `15000`
        description = `Dual socket, quad-core processing server with 1644 MHz Front Side Bus with 10Gb connectivity` )
      ( productid = `HT-1502` name = `Server Power Pro`
        suppliername = `Technocom` currencycode = `EUR` price = `25000`
        description = `Dual socket, quad-core processing server with 1644 MHz Front Side Bus with 100Gb connectivity` )
      ( productid = `HT-1600` name = `Family PC Basic`
        suppliername = `Titanium` currencycode = `EUR` price = `600`
        description = `2,8 Ghz dual core, 4 GB DDR3 SDRAM, 500 GB Hard Disc, Graphic Card: Proctra X, Windows 8` )
      ( productid = `HT-1601` name = `Family PC Pro`
        suppliername = `Titanium` currencycode = `EUR` price = `900`
        description = `2,8 Ghz dual core, 4 GB DDR3 SDRAM, 1000 GB Hard Disc, Graphic Card: Gladiator MX, Windows 8` )
      ( productid = `HT-1602` name = `Gaming Monster`
        suppliername = `Titanium` currencycode = `EUR` price = `1200`
        description = `3,4 Ghz quad core, 8 GB DDR3 SDRAM, 2000 GB Hard Disc, Graphic Card: Gladiator MX, Windows 8` )
      ( productid = `HT-1603` name = `Gaming Monster Pro`
        suppliername = `Titanium` currencycode = `EUR` price = `1700`
        description = `3,4 Ghz quad core, 16 GB DDR3 SDRAM, 4000 GB Hard Disc, Graphic Card: Hurricane GX, Windows 8` )
      ( productid = `HT-2000` name = `7" Widescreen Portable DVD Player w MP3`
        suppliername = `Titanium` currencycode = `EUR` price = `249.99`
        description = `7" LCD Screen, storage battery holds up to 6 hours!` )
      ( productid = `HT-2001` name = `10" Portable DVD player`
        suppliername = `Titanium` currencycode = `EUR` price = `449.99`
        description = `10" LCD Screen, storage battery holds up to 8 hours` )
      ( productid = `HT-2002` name = `Portable DVD Player with 9" LCD Monitor`
        suppliername = `Technocom` currencycode = `EUR` price = `853.99`
        description = `9" LCD Screen, storage holds up to 8 hours, 2 speakers included` )
      ( productid = `HT-2025` name = `CD/DVD case: 264 sleeves`
        suppliername = `Titanium` currencycode = `EUR` price = `44.99`
        description = `Organizer and protective case for 264 CDs and DVDs` )
      ( productid = `HT-2026` name = `Audio/Video Cable Kit - 4m`
        suppliername = `Titanium` currencycode = `EUR` price = `29.99`
        description = `Quality cables for notebooks and projectors` )
      ( productid = `HT-2027` name = `Removable CD/DVD Laser Labels`
        suppliername = `Titanium` currencycode = `EUR` price = `8.99`
        description = `Removable jewel case labels, zero residues (100)` )
      ( productid = `HT-6100` name = `Beam Breaker B-1`
        suppliername = `Titanium` currencycode = `EUR` price = `469`
        description = `720p, DLP Projector max. 8,45 Meter, 2D` )
      ( productid = `HT-6101` name = `Beam Breaker B-2`
        suppliername = `Technocom` currencycode = `EUR` price = `679`
        description = `1080p, DLP max.9,34 Meter, 2D-ready` )
      ( productid = `HT-6102` name = `Beam Breaker B-3`
        suppliername = `Technocom` currencycode = `EUR` price = `889`
        description = `1080p, DLP max. 12,3 Meter, 3D-ready` )
      ( productid = `HT-6110` name = `Play Movie`
        suppliername = `Fasttech` currencycode = `EUR` price = `130`
        description = `CD-RW, DVD+R/RW, DVD-R/RW, MPEG 2 (Video-DVD), MPEG 4, VCD, SVCD, DivX, Xvid` )
      ( productid = `HT-6111` name = `Record Movie`
        suppliername = `Fasttech` currencycode = `EUR` price = `288`
        description = `160 GB HDD, CD-RW, DVD+R/RW, DVD-R/RW, MPEG 2 (Video-DVD), MPEG 4, VCD, SVCD, DivX, Xvid` )
      ( productid = `HT-6120` name = `ITelo MusicStick`
        suppliername = `Fasttech` currencycode = `EUR` price = `45`
        description = `64 GB USB Music-on-Available-Stick` )
      ( productid = `HT-6121` name = `ITelo Jog-Mate`
        suppliername = `Fasttech` currencycode = `EUR` price = `63`
        description = `ITelo Jog-Mate 64 GB HDD and Color Display, can play movies` )
      ( productid = `HT-6122` name = `Power Pro Player 40`
        suppliername = `Fasttech` currencycode = `EUR` price = `167`
        description = `MP3-Player with 40 GB HDD and Color Display, can play movies` )
      ( productid = `HT-6123` name = `Power Pro Player 80`
        suppliername = `Fasttech` currencycode = `EUR` price = `299`
        description = `MP3-Player with 80 GB SSD and Color Display, can play movies` )
      ( productid = `HT-6130` name = `Flat Watch HD32`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `1459`
        description = `32-inch, 1366x768 Pixel, 16:9, HDTV ready` )
      ( productid = `HT-6131` name = `Flat Watch HD37`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `1199`
        description = `37-inch, 1366x768 Pixel, 16:9, HDTV ready` )
      ( productid = `HT-6132` name = `Flat Watch HD41`
        suppliername = `Very Best Screens` currencycode = `EUR` price = `899`
        description = `41-inch, 1366x768 Pixel, 16:9, HDTV ready` )
      ( productid = `HT-7000` name = `Copperberry`
        suppliername = `Fasttech` currencycode = `EUR` price = `549`
        description = `Our new multifunctional Handheld with phone function in copper` )
      ( productid = `HT-7010` name = `Silverberry`
        suppliername = `Fasttech` currencycode = `EUR` price = `549`
        description = `Our new multifunctional Handheld with phone function in silver` )
      ( productid = `HT-7020` name = `Goldberry`
        suppliername = `Fasttech` currencycode = `EUR` price = `549`
        description = `Our new multifunctional Handheld with phone function in gold` )
      ( productid = `HT-7030` name = `Platinberry`
        suppliername = `Fasttech` currencycode = `EUR` price = `549`
        description = `Our new multifunctional Handheld with phone function in platinum` )
      ( productid = `HT-8000` name = `ITelO FlexTop I4000`
        suppliername = `Titanium` currencycode = `EUR` price = `799`
        description = `Notebook with 2,80 GHz dual core, 4 GB DDR3 SDRAM, 500 GB Hard Disc, Windows 8` )
      ( productid = `HT-8001` name = `ITelO FlexTop I6300c`
        suppliername = `Titanium` currencycode = `EUR` price = `799`
        description = `Notebook with 2,80 GHz dual core, 8 GB DDR3 SDRAM, 500 GB Hard Disc, Windows 8` )
      ( productid = `HT-8002` name = `ITelO FlexTop I9100`
        suppliername = `Titanium` currencycode = `EUR` price = `1199`
        description = `Notebook with 2,80 GHz quad core, 4 GB DDR3 SDRAM, 1000 GB Hard Disc, Windows 8` )
      ( productid = `HT-8003` name = `ITelO FlexTop I9800`
        suppliername = `Titanium` currencycode = `EUR` price = `1388`
        description = `Notebook with 2,80 GHz quad core, 8 GB DDR3 SDRAM, 1000 GB Hard Disc, Windows 8` )
      ( productid = `HT-9991` name = `Smartphone Leather Case`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `25`
        description = `Button Clasp, Quality Material, 100% Leather, compatible with many smartphone models` )
      ( productid = `HT-9992` name = `Smartphone Alpha`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `599`
        description = `7 inch 1280x800 HD display (216 ppi), Quad-core processor, 16 GB internal storage (actual formatted capacity will be less), 4325 mAh battery (Up to 8 hours of active use), white or black` )
      ( productid = `HT-9993` name = `Mini Tablet`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `833`
        description = `7 inch 1280x800 HD display (216 ppi), Quad-core processor, 16 GB internal storage, 4325 mAh battery (Up to 8 hours of active use)` )
      ( productid = `HT-9994` name = `Camcorder View`
        suppliername = `Ultrasonic United` currencycode = `EUR` price = `1388`
        description = `1920x1080 Full HD, image stabilization reduces blur, 27x Optical / 32x Extended Zoom, wide angle Lens, 2.7" wide LCD display` )
      ( productid = `HT-9995` name = `Tablet Pouch`
        suppliername = `Titanium` currencycode = `EUR` price = `20`
        description = `Stylish tablet pouch, protects from scratches, color: black` )
      ( productid = `HT-9996` name = `Tablet Pouch`
        suppliername = `Titanium` currencycode = `EUR` price = `20`
        description = `Stylish tablet pouch, protects from scratches, color: black` )
      ( productid = `HT-9997` name = `e-Book Reader ReadMe`
        suppliername = `Titanium` currencycode = `EUR` price = `33`
        description = `6-Inch E Ink Screen, Access To e-book Store, Adjustable Font Styles and Sizes, Stores Up To 1,000 Books` )
      ( productid = `HT-9998` name = `Smartphone Beta`
        suppliername = `Titanium` currencycode = `EUR` price = `30`
        description = `5 Megapixel Camera, Wi-Fi 802.11 b/g/n, Bluetooth, GPS Available-GPS support` )
      ( productid = `HT-9999` name = `Maxi Tablet`
        suppliername = `Titanium` currencycode = `EUR` price = `749`
        description = `10.1-inch Multitouch HD Screen (1280 x 800), 16GB Internal Memory, Wireless N Wi-Fi; Bluetooth, GPS Enabled, 1GHz Dual-Core Processor` )
      ( productid = `PF-1000` name = `Flyer`
        suppliername = `Titanium` currencycode = `EUR` price = `0`
        description = `Flyer for our product palette` ) ).

  ENDMETHOD.

ENDCLASS.