protected void createTableViewer(Composite parent) {
    viewer =
        new FeatureTableViewer(
            parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);

    contentProvider = new LazyFeatureContentProvider();
    contentProvider.filter(featureLayer.filter());
    viewer.setContentProvider(contentProvider);

    // add columns
    DefaultFeatureTableColumn first = null;
    for (PropertyDescriptor prop : fs.getSchema().getDescriptors()) {
      if (Geometry.class.isAssignableFrom(prop.getType().getBinding())) {
        // skip Geometry
      } else {
        DefaultFeatureTableColumn column = new DefaultFeatureTableColumn(prop);
        // disable default sorting behaviour
        // column.setSortable( false );
        viewer.addColumn(column);
        first = first != null ? first : column;

        //                column.getViewerColumn().getColumn().addSelectionListener( new
        // SelectionAdapter() {
        //                    private SortOrder currentOrder = SortOrder.ASCENDING;
        //                    @Override
        //                    public void widgetSelected( SelectionEvent ev ) {
        //                        // with selection RAP produces huge JS which fails in browser
        //                        viewer.setSelection( StructuredSelection.EMPTY );
        //                        currentOrder = currentOrder.equals( ASCENDING ) ? DESCENDING :
        // ASCENDING;
        //                        contentProvider.sort( column, currentOrder );
        //                    }
        //                });
      }
    }

    // it is important to sort any column; otherwise preserving selection during refresh()
    // always selects a new element, which causes an event, which causes a refresh() ...
    first.sort(SWT.UP);

    //
    viewer.setInput(fs);

    // selection -> FeaturePanel
    viewer.addSelectionChangedListener(
        ev -> {
          on(ev.getSelection())
              .first(IFeatureTableElement.class)
              .ifPresent(
                  elm -> {
                    log.info("selection: " + elm);
                    featureLayer.setClicked(elm.unwrap(Feature.class).get());

                    BatikApplication.instance()
                        .getContext()
                        .openPanel(panel.site().path(), FeaturePanel.ID);
                  });
        });
  }