public FeatureSelectionTable(Composite parent, FeatureLayer featureLayer, IPanel panel) {
    BatikApplication.instance().getContext().propagate(this);
    this.featureLayer = featureLayer;
    this.fs = featureLayer.featureSource();
    this.panel = panel;

    parent.setLayout(FormLayoutFactory.defaults().create());

    // topbar
    Composite topbar = on(tk().createComposite(parent)).fill().noBottom().height(36).control();
    topbar.setLayout(FormLayoutFactory.defaults().spacing(10).margins(3).create());

    // closeBtn
    Button closeBtn = tk().createButton(topbar, "", SWT.PUSH, SWT.FLAT);
    closeBtn.setToolTipText("Close table");
    closeBtn.setImage(
        BatikPlugin.images()
            .svgImage(
                "close.svg", SvgImageRegistryHelper.NORMAL12)); // P4Plugin.TOOLBAR_ICON_CONFIG ) );
    on(closeBtn).left(0).top(0).height(26).width(28);
    closeBtn.addSelectionListener(
        selectionListener(
            ev -> {
              close();
            }));

    // title
    Label title = tk().createLabel(topbar, abbreviate(featureLayer.layer().label.get(), 20));
    title.setFont(MdAppDesign.font(FontStyle.Title));
    on(title).top(0, 1).left(closeBtn, -8);

    // seach
    createTextSearch(topbar);
    on(searchText.getControl()).left(title).top(0).width(250);

    // toolbar
    toolbar = tk().createToolbar(topbar, SWT.FLAT);
    on(toolbar.getControl()).fill().noLeft().right(100);
    ContributionManager.instance().contributeTo(toolbar, panel, TOOLBAR_TAG);

    // table viewer
    createTableViewer(parent);
    on(viewer.getTable()).fill().top(topbar);

    // listen to commit events
    EventManager.instance()
        .subscribe(
            this,
            TypeEventFilter.ifType(
                FeatureEvent.class,
                ev -> ev.getType() == Type.COMMIT && ev.getFeatureSource() == fs));

    // listen to click events
    EventManager.instance()
        .subscribe(
            this,
            TypeEventFilter.ifType(
                FeatureClickEvent.class,
                ev -> ev.getSource() == this.featureLayer && ev.clicked.isPresent()));
  }
 @Override
 public void dispose() {
   log.info("...");
   this.map = null;
   EventManager.instance().unsubscribe(projectNodeListener);
   EventManager.instance().unsubscribe(propertyListener);
   EventManager.instance().unsubscribe(styleListener);
 }
  @Override
  public void inputChanged(
      @SuppressWarnings("hiding") Viewer viewer, Object oldInput, Object newInput) {
    if (map != null) {
      dispose();
    }

    this.map = (IMap) newInput;
    this.viewer = (MapViewer) viewer;

    // listen to ProjectNodeCommitEvent
    projectNodeListener = new ProjectNodeListener();
    EventManager.instance()
        .subscribe(
            projectNodeListener,
            ifType(
                ProjectNodeCommittedEvent.class,
                ev -> {
                  ProjectNode src = ev.getEntity(map.belongsTo());
                  return src instanceof IMap && map.id().equals(src.id())
                      || src instanceof ILayer && map.containsLayer((ILayer) src);
                  // XXX check if structural change or just label changed
                }));

    // listen to LayerUserSettings#visible
    propertyListener = new PropertyListener();
    EventManager.instance()
        .subscribe(
            propertyListener,
            ifType(
                PropertyChangeEvent.class,
                ev -> {
                  if (ev.getSource() instanceof LayerUserSettings) {
                    String layerId = ((LayerUserSettings) ev.getSource()).layerId();
                    return map.layers
                        .stream()
                        .filter(l -> l.id().equals(layerId))
                        .findAny()
                        .isPresent();
                  }
                  return false;
                }));

    styleListener = new StyleListener();
    EventManager.instance()
        .subscribe(
            styleListener,
            ifType(
                FeatureStyleCommitedEvent.class,
                ev -> {
                  return map.layers
                      .stream()
                      .filter(l -> l.userSettings.get().visible.get())
                      .filter(l -> Objects.equals(l.styleIdentifier.get(), ev.getSource().id()))
                      .findAny()
                      .isPresent();
                }));
  }
 @EventHandler(display = true)
 protected void onFeatureChange(FeatureEvent ev) {
   if (!viewer.getTable().isDisposed()) {
     // XXX this tries to preserve selection; this is index based; it causes
     // a selection event; if sort has changed, another element ist selected!
     viewer.refresh();
   } else {
     EventManager.instance().unsubscribe(this);
   }
 }
 @EventHandler(display = true)
 protected void onFeatureClick(FeatureClickEvent ev) throws IOException {
   if (!viewer.getTable().isDisposed()) {
     IFeatureTableElement[] selected = viewer.getSelectedElements();
     String clickedFid = ev.clicked.get().getIdentifier().getID();
     if (selected.length != 1 || !selected[0].fid().equals(clickedFid)) {
       // viewer.setSelection() does not work with LazyContentProvider
       int index = contentProvider.indexOfFid(clickedFid);
       viewer.getTable().select(index);
       viewer.getTable().showSelection();
     }
   } else {
     EventManager.instance().unsubscribe(this);
   }
 }
  public Section createErweiterteDatenForm(Composite top) {

    Section formSection = newSection(top, "Gebäude");
    Composite parent = (Composite) formSection.getClient();

    final ActionButton openGebaeude =
        new ActionButton(
            parent,
            new Action("Gebäude bearbeiten") {

              @Override
              public void run() {
                GebaeudeComposite gebaeude = gebaudePicklist.getSelection();
                if (gebaeude != null) {
                  KapsPlugin.openEditor(fs, GebaeudeComposite.NAME, gebaeude);
                }
              }
            });
    openGebaeude.setLayoutData(left().left(35).right(55).height(25).top(null).create());
    openGebaeude.setEnabled(false);

    // Liste mit Wohnung + Auswählen daneben
    gebaudePicklist =
        new SimplePickList<GebaeudeComposite>(parent, pageSite) {

          @Override
          public SortedMap<String, GebaeudeComposite> getValues() {
            SortedMap<String, GebaeudeComposite> values = new TreeMap<String, GebaeudeComposite>();
            if (eigentum.objektNummer().get() != null) {
              Iterable<GebaeudeComposite> iterable = GebaeudeComposite.Mixin.forEntity(eigentum);
              for (GebaeudeComposite zone : iterable) {
                values.put(zone.schl().get(), zone);
              }
            }
            return values;
          }

          @Override
          public void onSelection(GebaeudeComposite selectedObject) {
            if (openGebaeude != null && !openGebaeude.isDisposed()) {
              openGebaeude.setEnabled(selectedObject != null);
            }
          }
        };
    gebaudePicklist.setLayoutData(
        right().left(10).right(30).height(25).top(null).bottom(100).create());
    gebaudePicklist.setEnabled(true);

    EventManager.instance()
        .subscribe(
            guh = new GebaeudeUpdateHandler(),
            new EventFilter<StoredPropertyChangeEvent>() {

              @Override
              public boolean apply(StoredPropertyChangeEvent input) {
                return input.getSource() instanceof GebaeudeComposite;
              }
            });

    createGebaeude =
        new ActionButton(
            parent,
            new Action("Gebäude anlegen") {

              @Override
              public void run() {
                if (eigentum.objektNummer().get() != null) {
                  Integer nummer =
                      KapsRepository.instance().gebaeudeNummern.get().generate(eigentum);

                  GebaeudeComposite gebaeude = repository.newEntity(GebaeudeComposite.class, null);
                  gebaeude.objektNummer().set(eigentum.objektNummer().get());
                  // suche nach höchster Gebäudenummer
                  gebaeude.gebaeudeNummer().set(nummer);
                  // wohnung.vertrag().set( flurstueck.vertrag().get() );
                  KapsPlugin.openEditor(fs, GebaeudeComposite.NAME, gebaeude);
                  gebaudePicklist.setEnabled(true);
                }
              }
            });
    createGebaeude.setLayoutData(left().left(75).right(95).height(25).top(null).create());
    createGebaeude.setEnabled(true);

    return formSection;
  }