public Control createExampleControl(Composite parent) {
    DefaultGridLayer gridLayer =
        new DefaultGridLayer(
            RowDataListFixture.getList(),
            RowDataListFixture.getPropertyNames(),
            RowDataListFixture.getPropertyToLabelMap());

    DataLayer columnHeaderDataLayer = (DataLayer) gridLayer.getColumnHeaderDataLayer();
    columnHeaderDataLayer.setConfigLabelAccumulator(new ColumnLabelAccumulator());

    final DataLayer bodyDataLayer = (DataLayer) gridLayer.getBodyDataLayer();
    IDataProvider dataProvider = bodyDataLayer.getDataProvider();

    // NOTE: Register the accumulator on the body data layer.
    // This ensures that the labels are bound to the column index and are unaffected by column
    // order.
    final ColumnOverrideLabelAccumulator columnLabelAccumulator =
        new ColumnOverrideLabelAccumulator(bodyDataLayer);
    bodyDataLayer.setConfigLabelAccumulator(columnLabelAccumulator);

    NatTable natTable = new NatTable(parent, gridLayer, false);

    natTable.addConfiguration(new DefaultNatTableStyleConfiguration());
    natTable.addConfiguration(new HeaderMenuConfiguration(natTable));
    natTable.addConfiguration(editableGridConfiguration(columnLabelAccumulator, dataProvider));

    final ColumnHeaderCheckBoxPainter columnHeaderCheckBoxPainter =
        new ColumnHeaderCheckBoxPainter(bodyDataLayer);
    final ICellPainter column9HeaderPainter =
        new BeveledBorderDecorator(
            new CellPainterDecorator(
                new TextPainter(), CellEdgeEnum.RIGHT, columnHeaderCheckBoxPainter));
    natTable.addConfiguration(
        new AbstractRegistryConfiguration() {
          public void configureRegistry(IConfigRegistry configRegistry) {
            configRegistry.registerConfigAttribute(
                CellConfigAttributes.CELL_PAINTER,
                column9HeaderPainter,
                DisplayMode.NORMAL,
                ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + 9);
          }

          @Override
          public void configureUiBindings(UiBindingRegistry uiBindingRegistry) {
            uiBindingRegistry.registerFirstSingleClickBinding(
                new CellPainterMouseEventMatcher(
                    GridRegion.COLUMN_HEADER,
                    MouseEventMatcher.LEFT_BUTTON,
                    columnHeaderCheckBoxPainter),
                new ToggleCheckBoxColumnAction(columnHeaderCheckBoxPainter, bodyDataLayer));
          }
        });

    natTable.configure();

    return natTable;
  }
    public CalculatingBodyLayerStack(
        EventList<NumberValues> valuesToShow, ConfigRegistry configRegistry) {
      final CachedValueCalculatingDataProvider<NumberValues> dataProvider =
          new CachedValueCalculatingDataProvider<NumberValues>(
              valuesToShow, new BasicDataColumnAccessor());
      bodyDataLayer = new DataLayer(dataProvider);
      // adding this listener will trigger updates on data changes
      bodyDataLayer.addLayerListener(
          new ILayerListener() {
            @Override
            public void handleLayerEvent(ILayerEvent event) {
              if (event instanceof IVisualChangeEvent) {
                dataProvider.valueCache.clearCache();
              }
            }
          });
      // register a layer listener to ensure the value cache gets disposed
      bodyDataLayer.registerCommandHandler(
          new ILayerCommandHandler<DisposeResourcesCommand>() {

            @Override
            public boolean doCommand(ILayer targetLayer, DisposeResourcesCommand command) {
              dataProvider.valueCache.dispose();
              return false;
            }

            @Override
            public Class<DisposeResourcesCommand> getCommandClass() {
              return DisposeResourcesCommand.class;
            }
          });

      // connect the DataLayer with the data provider so the value cache knows how to fire updates
      dataProvider.setCacheEventLayer(bodyDataLayer);

      glazedListsEventLayer = new GlazedListsEventLayer<NumberValues>(bodyDataLayer, valuesToShow);
      summaryRowLayer = new SummaryRowLayer(glazedListsEventLayer, configRegistry, false);
      summaryRowLayer.addConfiguration(
          new CalculatingSummaryRowConfiguration(bodyDataLayer.getDataProvider()));
      columnReorderLayer = new ColumnReorderLayer(summaryRowLayer);
      columnHideShowLayer = new ColumnHideShowLayer(columnReorderLayer);
      selectionLayer = new SelectionLayer(columnHideShowLayer);
      viewportLayer = new ViewportLayer(selectionLayer);
      setUnderlyingLayer(viewportLayer);

      registerCommandHandler(new CopyDataCommandHandler(selectionLayer));
    }
  public CalculatingBodyLayerStack(
      EventList<NumberValues> valuesToShow, ConfigRegistry configRegistry) {
    IDataProvider dataProvider =
        new GlazedListsDataProvider<NumberValues>(valuesToShow, new CalculatingDataProvider());
    bodyDataLayer = new DataLayer(dataProvider);
    glazedListsEventLayer = new GlazedListsEventLayer<NumberValues>(bodyDataLayer, valuesToShow);
    summaryRowLayer = new SummaryRowLayer(glazedListsEventLayer, configRegistry, false);
    summaryRowLayer.addConfiguration(
        new CalculatingSummaryRowConfiguration(bodyDataLayer.getDataProvider()));
    columnReorderLayer = new ColumnReorderLayer(summaryRowLayer);
    columnHideShowLayer = new ColumnHideShowLayer(columnReorderLayer);
    selectionLayer = new SelectionLayer(columnHideShowLayer);
    viewportLayer = new ViewportLayer(selectionLayer);
    setUnderlyingLayer(viewportLayer);

    registerCommandHandler(new CopyDataCommandHandler(selectionLayer));
  }
  @Override
  public Control createExampleControl(Composite parent) {
    // create a new ConfigRegistry which will be needed for GlazedLists
    // handling
    ConfigRegistry configRegistry = new ConfigRegistry();

    String[] propertyNames = {"name", "age", "money", "gender", "city"};

    // mapping from property to label, needed for column header labels
    Map<String, String> propertyToLabelMap = new HashMap<>();
    propertyToLabelMap.put("name", "Name");
    propertyToLabelMap.put("age", "Age");
    propertyToLabelMap.put("money", "Money");
    propertyToLabelMap.put("gender", "Gender");
    propertyToLabelMap.put("city", "City");

    IColumnPropertyAccessor<MyRowObject> columnPropertyAccessor =
        new ReflectiveColumnPropertyAccessor<>(propertyNames);

    BodyLayerStack<MyRowObject> bodyLayerStack =
        new BodyLayerStack<>(createMyRowObjects(50), columnPropertyAccessor);
    // add a label accumulator to be able to register converter
    bodyLayerStack.getBodyDataLayer().setConfigLabelAccumulator(new ColumnLabelAccumulator());

    // build the column header layer
    IDataProvider columnHeaderDataProvider =
        new DefaultColumnHeaderDataProvider(propertyNames, propertyToLabelMap);
    DataLayer columnHeaderDataLayer = new DefaultColumnHeaderDataLayer(columnHeaderDataProvider);
    ILayer columnHeaderLayer =
        new ColumnHeaderLayer(
            columnHeaderDataLayer, bodyLayerStack, bodyLayerStack.getSelectionLayer());

    // Note: The column header layer is wrapped in a filter row composite.
    // This plugs in the filter row functionality
    FilterRowHeaderComposite<MyRowObject> filterRowHeaderLayer =
        new FilterRowHeaderComposite<>(
            new DefaultGlazedListsFilterStrategy<>(
                bodyLayerStack.getFilterList(), columnPropertyAccessor, configRegistry),
            columnHeaderLayer,
            columnHeaderDataLayer.getDataProvider(),
            configRegistry);

    // build the row header layer
    IDataProvider rowHeaderDataProvider =
        new DefaultRowHeaderDataProvider(bodyLayerStack.getBodyDataProvider());
    DataLayer rowHeaderDataLayer = new DefaultRowHeaderDataLayer(rowHeaderDataProvider);
    ILayer rowHeaderLayer =
        new RowHeaderLayer(rowHeaderDataLayer, bodyLayerStack, bodyLayerStack.getSelectionLayer());

    // build the corner layer
    IDataProvider cornerDataProvider =
        new DefaultCornerDataProvider(columnHeaderDataProvider, rowHeaderDataProvider);
    DataLayer cornerDataLayer = new DataLayer(cornerDataProvider);
    ILayer cornerLayer = new CornerLayer(cornerDataLayer, rowHeaderLayer, filterRowHeaderLayer);

    // build the grid layer
    GridLayer gridLayer =
        new GridLayer(bodyLayerStack, filterRowHeaderLayer, rowHeaderLayer, cornerLayer);

    // turn the auto configuration off as we want to add our header menu
    // configuration
    NatTable natTable = new NatTable(parent, gridLayer, false);

    // as the autoconfiguration of the NatTable is turned off, we have to
    // add the
    // DefaultNatTableStyleConfiguration and the ConfigRegistry manually
    natTable.setConfigRegistry(configRegistry);
    natTable.addConfiguration(new DefaultNatTableStyleConfiguration());
    // add filter row configuration
    natTable.addConfiguration(new FilterRowConfiguration());
    natTable.addConfiguration(new MyRowObjectTableConfiguration());

    natTable.addConfiguration(
        new HeaderMenuConfiguration(natTable) {
          @Override
          protected PopupMenuBuilder createCornerMenu(NatTable natTable) {
            return super.createCornerMenu(natTable).withStateManagerMenuItemProvider();
          }
        });

    natTable.configure();

    natTable.registerCommandHandler(new DisplayPersistenceDialogCommandHandler(natTable));

    return natTable;
  }