de.unioninvestment.eai.portal.portlet.crud.domain.model.Table.java Source code

Java tutorial

Introduction

Here is the source code for de.unioninvestment.eai.portal.portlet.crud.domain.model.Table.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package de.unioninvestment.eai.portal.portlet.crud.domain.model;

import com.vaadin.data.Validator;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.ui.Table.ColumnGenerator;
import de.unioninvestment.eai.portal.portlet.crud.config.TableConfig;
import de.unioninvestment.eai.portal.portlet.crud.domain.container.GeneratedColumnsDataStreamWrapper;
import de.unioninvestment.eai.portal.portlet.crud.domain.events.*;
import de.unioninvestment.eai.portal.portlet.crud.domain.model.DataContainer.ExportWithExportSettings;
import de.unioninvestment.eai.portal.portlet.crud.domain.model.container.DataStream;
import de.unioninvestment.eai.portal.portlet.crud.domain.support.EmptyColumnGenerator;
import de.unioninvestment.eai.portal.support.vaadin.mvp.EventRouter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.*;

import static java.util.Collections.singleton;
import static java.util.Collections.unmodifiableSet;

/**
 * Modell-Klasse fr Tabellen.
 * 
 * @author max.hartmann
 * @author Jan Malcomess (codecentric AG)
 * 
 */
public class Table extends Component implements Component.ExpandableComponent, Serializable {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = LoggerFactory.getLogger(Table.class);

    /**
    * Permission Actions.
    */
    public enum Permission {
        BUILD, EDIT
    }

    /**
     * Renderer-Klasse fr Zeilen-Styles.
     */
    public static interface RowStyleRenderer {
        /**
         * @param rowId
         *            ZeilenId
         * @return den Style der Zeile.
         */
        public String getStyle(ContainerRowId rowId);
    }

    /**
     * Renderer-Klasse fr Spalten-Styles.
     */
    public static interface ColumnStyleRenderer {
        /**
         * @param rowId
         *            ZeilenId
         * @return den Style der Spalte.
         */
        public String getStyle(ContainerRowId rowId);
    }

    /**
     * Definiert die Erwartungen des Models an den Presenter.
     * 
     * @author eugen.melnichuk
     */
    public interface Presenter {

        /**
         * Fgt der Tabelle dynamisch eine neue Spalte hinzu.
         * 
         * @param columnName
         *            die ID der Spalte
         * @param columnTitle
         *            die berschrift der Spalte
         * @param columnGenerator
         *            der Generator, der den Inhalt der einzelnen Zellen
         *            generiert
         */
        void addGeneratedColumn(String columnName, String columnTitle, ColumnGenerator columnGenerator);

        /**
         * Entfernt eine zuvor per
         * {@link #addGeneratedColumn(String, String, ColumnGenerator)} hinzugefgte
         * Spalte aus der Tabelle.
         * 
         * @param columnName
         *            der Name der Spalte, die bei
         *            {@link #addGeneratedColumn(String, String, ColumnGenerator)}
         *            verwendet wurde
         */
        void removeGeneratedColumn(String columnName);

        /**
         * Fhrt nderungen an der Tabelle zu wie beispielsweise dynamisches
         * Hinzufgen und Entfernen von Spalten. Das Content-Refreshing
         * (Rerendering) wird vor dem Ausfhren von {@code change} ausgeschaltet
         * und (falls es vorher eingeschaltet war) danach wieder eingeschaltet.
         * 
         * @param changes
         *            die durchzufhrenden nderungen
         */
        public void renderOnce(DynamicColumnChanges changes);

        /**
         * @param columnName
         *            der Spaltenname
         * @return {@code true} wenn die Tabelle eine per
         *         {@link #addGeneratedColumn(String, String, ColumnGenerator)}
         *         hinzugefgte Spalte hat
         */
        public boolean hasGeneratedColumn(String columnName);

        /**
         * Entfernt alle per
         * {@link #addGeneratedColumn(String, String, ColumnGenerator)} hinzugefgten
         * Spalten.
         */
        public void clearAllGeneratedColumns();

        /**
         * @return die Namen der sichtbaren Spalten in der Reihenfolge, in der
         *         sie angezeigt werden.
         * @see #setVisibleColumns(List)
         */
        public List<String> getVisibleColumns();

        /**
         * Setzt gleichzeitig die Reihenfolge und die Sichtbarkeit der Spalten.
         * Alle Spalten, deren ID in der bergebenen Liste
         * {@code visibleColumns} enthalten sind, werden angezeigt, alle anderen
         * nicht. Das bezieht sich nicht nur auf per {@code addGeneratedColumn}
         * hinzugefgten Spalten sondern auf alle Spalten inkl. der fest in der
         * Konfiguration deklarierten. Die Spalten werden in der Reihenfolge
         * angeordnet, wie sie in {@code visibleColumns} stehen.
         * 
         * @param visibleColumns
         *            die Liste der ColumnNames. Fr eine per
         *            {@link #addGeneratedColumn(String, String, com.vaadin.ui.Table.ColumnGenerator)}
         *            hinzugefgte Spalten ist das der String, der dabei als
         *            Argument {@code columnName} verwendet wurde, fr eine
         *            deklarierte Spalte das Attribut {@code name}
         */
        public void setVisibleColumns(List<String> visibleColumns);

        /**
         * Setzt die Sichtbarkeit der TableAction (Button) mit der ID {@code id}
         * .
         * 
         * @param id
         *            die ID der TableAction, so wie sie im Attribut <tt>id</tt>
         *            des Tags <tt>action</tt> definiert ist.
         * 
         * @param visible
         *            {@code true}: sichtbar, {@code false}: unsichtbar,
         */
        public void setTableActionVisibility(String id, boolean visible);

        /**
         * Fgt der Tabelle eine neue Zeile hinzu. Werte der Zeile knnen ber
         * {@code values} vorbelegt werden.
         * 
         * @param values
         *            die Werte, die in der neuen Zeile bereits gesetzt sein
         *            sollen. Die Keys der Map entsprechen den Column Names, die
         *            dazugehrigen Values sind die Werte in der Zeile.
         */
        public ContainerRow createNewRow(Map<String, Object> values);

        void download(Download download);

        /**
         * Verwirft die nderungen auf der Tabelle.
         */
        public void revertChanges();
    }

    /**
     * Ein Wrapper fr eine Reihe von
     * {@link Table.Presenter#addGeneratedColumn(String, String, com.vaadin.ui.Table.ColumnGenerator)}
     * and {@link Table.Presenter#removeGeneratedColumn(String)} Anweisungen.
     * 
     * @author Bastian Krol
     */
    public interface DynamicColumnChanges {

        /**
         * Wendet die nderungen an. {@code addGeneratedColum} und
         * {@code removeGeneratedColumn} Anweisungen sollten in dieser Methode
         * ausgefhrt werden.
         */
        public void apply();
    }

    /**
     * Ansichtsmodus der Tabellen-Komponente.
     */
    public enum Mode {
        VIEW, EDIT
    };

    public enum DisplayMode {
        TABLE, FORM
    }

    public enum SelectionMode {
        DISABLED, SINGLE, MULTIPLE
    }

    private final TableConfig config;
    private final TableColumns columns;
    private DataContainer container;
    private List<TableAction> actions;

    private RowStyleRenderer rowStyleRenderer;

    private EventRouter<SelectionEventHandler, SelectionEvent> selectionEventRouter = new EventRouter<SelectionEventHandler, SelectionEvent>();
    private EventRouter<TableDoubleClickEventHandler, TableDoubleClickEvent> doubleClickEventRouter = new EventRouter<TableDoubleClickEventHandler, TableDoubleClickEvent>();
    private EventRouter<ModeChangeEventHandler<Table, Mode>, ModeChangeEvent<Table, Mode>> editModeChangeEventRouter = new EventRouter<ModeChangeEventHandler<Table, Mode>, ModeChangeEvent<Table, Mode>>();
    private EventRouter<ModeChangeEventHandler<Table, DisplayMode>, ModeChangeEvent<Table, DisplayMode>> displayModeChangeEventRouter = new EventRouter<ModeChangeEventHandler<Table, DisplayMode>, ModeChangeEvent<Table, DisplayMode>>();
    private EventRouter<RowChangeEventHandler, RowChangeEvent> rowChangeEventRouter = new EventRouter<RowChangeEventHandler, RowChangeEvent>();
    private EventRouter<InitializeEventHandler<Table>, InitializeEvent<Table>> initializeEventRouter = new EventRouter<InitializeEventHandler<Table>, InitializeEvent<Table>>();

    Mode mode = null;
    DisplayMode displayMode = DisplayMode.TABLE;

    private Set<ContainerRowId> selection = new LinkedHashSet<ContainerRowId>();
    private final boolean editable;
    private final boolean directEdit;

    private RowEditableChecker editableChecker;
    private RowDeletableChecker deletableChecker;

    private Table.Presenter presenter;

    private Validator rowValidator = null;

    private SelectionMode selectionMode;

    /**
     * Konstruktor mit Parametern.
     *  @param config
     *            Konfiguration der Tabelle
     * @param tableColumns
     *            Tabellen-Spalten
      * @param container
      *          the underlying data container
      * @param editable
      *          the editable status of the table itself (not dependent on container)
      */
    public Table(TableConfig config, TableColumns tableColumns, DataContainer container, boolean editable,
            boolean directEdit) {
        this.config = config;
        this.editable = editable;
        this.directEdit = directEdit;
        this.selectionMode = SelectionMode.valueOf(config.getSelectionMode().name());

        this.columns = tableColumns;
        if (columns != null) {
            columns.setTable(this);
        }

        this.container = container;
        if (selectionMode == SelectionMode.DISABLED && isEditable()) {
            LOGGER.warn("Table is editable but selection mode is 'disabled'");
        }
    }

    /**
     * Setzt den Presenter im Modell fr den Fall, dass Ereignisse im Modell
     * Auswirkungen auf die Prsentation der Tabelle haben. Der Presenter darf
     * in der Table nur ber das Interface {@link Table.Presenter} angesprochen
     * werden.
     * 
     * @param presenter
     *            der Presenter
     */
    public void setPresenter(Table.Presenter presenter) {
        this.presenter = presenter;
    }

    public String getId() {
        return config.getId();
    }

    /**
     * @since 1.45
     */
    public String getWidth() {
        return this.config.getWidth();
    }

    /**
     * @since 1.45
     */
    public String getHeight() {
        return this.config.getHeight();
    }

    public RowStyleRenderer getRowStyleRenderer() {
        return rowStyleRenderer;
    }

    public void setRowStyleRenderer(RowStyleRenderer rowStyleRenderer) {
        this.rowStyleRenderer = rowStyleRenderer;
    }

    public void setRowEditableChecker(RowEditableChecker checker) {
        this.editableChecker = checker;
    }

    public void setRowDeletableChecker(RowDeletableChecker checker) {
        this.deletableChecker = checker;
    }

    /**
     * Holt fr jedes Column den jeweiligen ColumnStyleRenderer.
     * 
     * @param columnName
     *            Tabellenspaltenname
     * @return ColumnStyleRenderer
     */
    public ColumnStyleRenderer getColumnStyleRenderer(String columnName) {
        if (columns != null) {
            if (columns.contains(columnName)) {
                TableColumn tableColumn = columns.get(columnName);
                if (tableColumn != null) {
                    return tableColumn.getColumnStyleRenderer();
                }
            }
        }
        return null;
    }

    /**
     * Liefert die Zeilenhhe zurck.
     * 
     * @return Zeilenhhe
     */
    public Integer getRowHeight() {
        if (config.getColumns() == null) {
            // no further configuration of columns (multiline), so always use
            // default height
            return null;
        } else {
            return config.getRowHeight();
        }
    }

    public boolean isSortingEnabled() {
        return config.isSortable();
    }

    public DataContainer getContainer() {
        return container;
    }

    public TableColumns getColumns() {
        return columns;
    }

    public List<TableAction> getActions() {
        return Collections.unmodifiableList(actions);
    }

    void setActions(List<TableAction> buildTableActions) {
        this.actions = buildTableActions;
    }

    /**
     * @param selection
     *            die im View genderte Selektion.
     */
    public void changeSelection(Set<ContainerRowId> selection) {
        LinkedHashSet<ContainerRowId> newSelection = new LinkedHashSet<ContainerRowId>(selection);
        if (!newSelection.equals(this.selection)) {
            this.selection = newSelection;
            selectionEventRouter.fireEvent(new SelectionEvent(this, unmodifiableSet(this.selection)));
        }
    }

    /**
     * Verarbeitet den Doppelklick auf eine Zeile.
     * 
     * @param row
     *            Zeile
     */
    public void doubleClick(ContainerRow row) {
        if (config.isEditForm()
                && (doubleClickEventRouter.getRegisteredHandlerSize() == 0 || getMode() == Mode.EDIT)) {

            changeDisplayMode(DisplayMode.FORM);
            changeSelection(singleton(row.getId()));
        } else {
            doubleClickEventRouter.fireEvent(new TableDoubleClickEvent(this, row));
        }
    }

    public boolean isDirectEdit() {
        return directEdit;
    }

    public void changeMode() {
        Mode newMode = getMode() == Mode.VIEW ? Mode.EDIT : Mode.VIEW;
        changeMode(newMode);
    }

    /**
     * @param mode
     *            der im View gesetzte Modus
     */
    public void changeMode(Mode mode) {
        if (directEdit) {
            throw new IllegalStateException("Cannot change mode if direct editing is enabled");
        } else if (getMode() != mode) {
            this.mode = mode;
            editModeChangeEventRouter.fireEvent(new ModeChangeEvent<Table, Mode>(this, mode));
        }
    }

    public void changeDisplayMode() {
        DisplayMode newDisplayMode = displayMode == DisplayMode.TABLE ? DisplayMode.FORM : DisplayMode.TABLE;
        changeDisplayMode(newDisplayMode);
    }

    /**
     * @param newDisplayMode
     *            der im View gesetzte Modus
     */
    public void changeDisplayMode(DisplayMode newDisplayMode) {
        if (newDisplayMode == DisplayMode.FORM && !isFormEditEnabled()) {
            throw new IllegalStateException("Cannot change displayMode if form editing is disabled");
        } else if (this.displayMode != newDisplayMode) {
            this.displayMode = newDisplayMode;
            displayModeChangeEventRouter.fireEvent(new ModeChangeEvent<Table, DisplayMode>(this, newDisplayMode));
        }
    }

    /**
     * Fgt einen Event Handler fr die nderung des Anzeigemodus hinzu.
     * 
     * @param handler
     *            Event Handler
     */
    public void addDisplayModeChangeEventHandler(ModeChangeEventHandler<Table, DisplayMode> handler) {
        displayModeChangeEventRouter.addHandler(handler);
    }

    /**
     * Fgt ein SelectionEventHandler hinzu.
     * 
     * @param selectionEventHandler
     *            EventHandler
     */
    public void addSelectionEventHandler(SelectionEventHandler selectionEventHandler) {
        selectionEventRouter.addHandler(selectionEventHandler);
    }

    /**
     * Fgt einen TableDoubleClickEventHandler hinzu.
     * 
     * @param handler
     *            Eventhandler
     */
    public void addDoubleClickEventHandler(TableDoubleClickEventHandler handler) {
        doubleClickEventRouter.addHandler(handler);
    }

    public void removeDoubleClickEventHandler(TableDoubleClickEventHandler doubleClickEventHandler) {
        doubleClickEventRouter.removeHandler(doubleClickEventHandler);
    }

    /**
     * Fgt ein ModeChangeEventHandler hinzu.
     * 
     * @param onEditEventHandler
     *            EventHandler
     */
    public void addModeChangeEventHandler(ModeChangeEventHandler<Table, Mode> onEditEventHandler) {
        editModeChangeEventRouter.addHandler(onEditEventHandler);
    }

    /**
     * Wird durch die Table-UI-Komponente nach nderung einer Zeile im Container
     * aufgerufen.
     * 
     * @param uncommittedRowId
     *            die gerade im UI genderte Zeile
     * @param changedValues
     *            Genderten Werte als Map
     */
    public void rowChange(ContainerRowId uncommittedRowId, Map<String, Object> changedValues) {
        ContainerRow containerRow = container.getRow(uncommittedRowId, false, false);
        rowChangeEventRouter.fireEvent(new RowChangeEvent(containerRow, changedValues));
    }

    public void validateIfChanged(ContainerRowId uncommittedRowId) throws InvalidValueException {
        if (rowValidator != null) {
            ContainerRow containerRow = container.getRow(uncommittedRowId, false, true);
            if (containerRow.isModified() || containerRow.isNewItem()) {
                rowValidator.validate(containerRow);
            }
        }
    }

    public void doInitialize() {
        initializeEventRouter.fireEvent(new InitializeEvent<Table>(this));
    }

    public Set<ContainerRowId> getSelection() {
        return unmodifiableSet(selection);
    }

    /**
     * Prft, ob die Tabelle generell editierbar oder schreibgeschtzt ist. Dies
     * sagt allerdings noch nichts darber aus, ob eine bestimmte Zeile
     * editierbar ist, dazu muss {@link #isRowEditable(ContainerRow)} aufgerufen
     * werden.
     * 
     * @return ob die Tabelle generell editiert werden kann
     */
    public boolean isEditable() {
        return editable && (container.isInsertable() || container.isUpdateable() || container.isDeleteable());
    }

    public boolean isModeChangeable() {
        return isEditable() && !isDirectEdit();
    }

    /**
     * Prft, ob die aktuelle Zeile editiert werden darf.
     * 
     * @param row
     *            die Zeile
     * @return ob die aktuelle Zeile editiert werden darf
     */
    public boolean isRowEditable(ContainerRow row) {
        if (!isEditable()) {
            return false;
        }
        if (editableChecker != null && !editableChecker.isEditable(row)) {
            return false;
        }
        return true;
    }

    /**
     * Prft, ob die aktuelle Zeile gelscht werden darf.
     * 
     * @param rowId
     *            die ID der Zeile
     * @return ob die aktuelle Zeile gelscht werden darf
     */
    public boolean isRowDeletable(ContainerRowId rowId) {
        boolean rowIsDeletable = true;
        if (deletableChecker != null) {
            ContainerRow row = container.getRow(rowId, false, true);
            rowIsDeletable = deletableChecker.isDeletable(row);
        }
        return rowIsDeletable;
    }

    /**
     * Aktualisiert die Daten im Container aus der DB.
     */
    public void refresh() {
        container.refresh();
    }

    /**
     * Fgt einen rowChange-Eventhandler hinzu.
     * 
     * @param rowChangeEventHandler
     *            EventHandler
     */
    public void addRowChangeEventHandler(RowChangeEventHandler rowChangeEventHandler) {

        rowChangeEventRouter.addHandler(rowChangeEventHandler);
    }

    public void addInitializeEventHandler(InitializeEventHandler<Table> eventHandler) {
        initializeEventRouter.addHandler(eventHandler);
    }

    public boolean isFormEditEnabled() {
        return config.isEditForm();
    }

    /**
     * @return if the table is exportable
     * @deprecated Export should no longer be configured globally, but instead
     *             use special export-actions.
     * @see TableAction#isExportAction()
     */
    public boolean isExport() {
        return config.getExport() != null;
    }

    /**
     * @return the export format
     * @deprecated Export should no longer be configured globally, but instead
     *             use special export-actions.
     * @see TableAction#getExportType()
     */
    public String getExportType() {
        return config.getExport().value();
    }

    /**
     * @return Anzahl angezeigter Zeilen
     */
    public int getPageLength() {
        return config.getPageLength();
    }

    /**
     * @return Fakrot gerenderter Zeilen im Verhltnis zur page-length
     */
    public double getCacheRate() {
        return config.getCacheRate();
    }

    /**
     * Fgt der Tabelle dynamisch eine neue Spalte hinzu. Wenn die notwendigen
     * Berechtigungen fehlen, werden leere Spalten generiert.
     * 
     * @param columnName
     *            der Name der Spalte
     * @param columnTitle
     *            die berschrift der Spalte
     * @param columnGenerator
     *            der Generator, der den Inhalt der einzelnen Zellen generiert
     */
    public void addGeneratedColumn(String columnName, String columnTitle, ColumnGenerator columnGenerator) {
        if (getPortlet().allowsDisplayGeneratedContent()) {
            presenter.addGeneratedColumn(columnName, columnTitle, columnGenerator);
        } else {
            presenter.addGeneratedColumn(columnName, columnTitle, new EmptyColumnGenerator());
        }
    }

    private Portlet getPortlet() {
        return getPanel().getPortlet();
    }

    /**
     * Entfernt eine zuvor per
     * {@link #addGeneratedColumn(String, String, ColumnGenerator)} hinzugefgte Spalte
     * aus der Tabelle.
     * 
     * @param columnId
     *            die ID der Spalte, die bei
     *            {@link #addGeneratedColumn(String, String, ColumnGenerator)} verwendet
     *            wurde
     */
    public void removeGeneratedColumn(String columnId) {
        presenter.removeGeneratedColumn(columnId);
    }

    /**
     * Gibt die ContainerRow zur bergebenen {@code itemId} aus der
     * Vaadin-Table/dem Vaadin-Container zurck.
     * 
     * @param itemId
     *            die Vaadin-ID der Zeile
     * @return die Modell-Zeile
     */
    public ContainerRow getRowByItemId(Object itemId) {
        ContainerRowId rowId = container.convertInternalRowId(itemId);
        return getRow(rowId);
    }

    /**
     * Gibt die ContainerRow zur bergebenen {@code rowId} zurck.
     * 
     * @param rowId
     *            die ID der Zeile
     * @return die Zeile
     */
    public ContainerRow getRow(ContainerRowId rowId) {
        return container.getRow(rowId, false, true);
    }

    /**
     * Fhrt nderungen an der Tabelle zu wie beispielsweise dynamisches
     * Hinzufgen und Entfernen von Spalten. Das Content-Refreshing
     * (Rerendering) wird vor dem Ausfhren von {@code change} ausgeschaltet und
     * (falls es vorher eingeschaltet war) danach wieder eingeschaltet.
     * 
     * @param changes
     *            die durchzufhrenden nderungen
     */
    public void renderOnce(DynamicColumnChanges changes) {
        presenter.renderOnce(changes);
    }

    /**
     * @param columnId
     *            die Spalten-ID/Spalten-berschrift.
     * @return {@code true} wenn die Tabelle eine per
     *         {@link #addGeneratedColumn(String, String, ColumnGenerator)} hinzugefgte
     *         Spalte hat.
     */
    public boolean hasGeneratedColumn(String columnId) {
        return presenter.hasGeneratedColumn(columnId);
    }

    /**
     * Entfernt alle per {@link #addGeneratedColumn(String, String, ColumnGenerator)}
     * hinzugefgten Spalten.
     */
    public void clearAllGeneratedColumns() {
        presenter.clearAllGeneratedColumns();
    }

    /**
     * @return die IDs der sichtbaren Spalten in der Reihenfolge, in der sie
     *         angezeigt werden.
     * @see #setVisibleColumns(List)
     */
    public List<String> getVisibleColumns() {
        return presenter.getVisibleColumns();
    }

    /**
     * Setzt gleichzeitig die Reihenfolge und die Sichtbarkeit der Spalten. Alle
     * Spalten, deren ID in der bergebenen Liste {@code visibleColumns}
     * enthalten sind, werden angezeigt, alle anderen nicht. Das bezieht sich
     * nicht nur auf per {@code addGeneratedColumn} hinzugefgten Spalten
     * sondern auf alle Spalten inkl. der fest in der Konfiguration
     * deklarierten. Die Spalten werden in der Reihenfolge angeordnet, wie sie
     * in {@code visibleColumns} stehen.
     * 
     * @param visibleColumns
     *            die Liste der ColumnNames. Fr eine per
     *            {@link #addGeneratedColumn(String, String, ColumnGenerator)}
     *            hinzugefgte Spalten ist das der String, der dabei als
     *            Argument {@code columnName} verwendet wurde, fr eine
     *            deklarierte Spalte das Attribut {@code name}
     */
    public void setVisibleColumns(List<String> visibleColumns) {
        presenter.setVisibleColumns(visibleColumns);
    }

    /**
     * Fgt der Tabelle eine neue Zeile hinzu. Werte der Zeile knnen ber
     * {@code values} vorbelegt werden.
     * 
     * @param values
     *            die Werte, die in der neuen Zeile bereits gesetzt sein sollen.
     *            Die Keys der Map entsprechen den Column Names, die
     *            dazugehrigen Values sind die Werte in der Zeile.
     * @return die neu angelegte Zeile
     */
    public ContainerRow createNewRow(Map<String, Object> values) {
        // Ggf. vorhandene nderungen in der alten Zeile vorher committen
        container.commit();
        return presenter.createNewRow(values);
    }

    /**
     * Setzt die Sichtbarkeit der TableAction (Button) mit der ID {@code id}.
     * 
     * @param id
     *            die ID der TableAction, so wie sie im Attribut <tt>id</tt> des
     *            Tags <tt>action</tt> definiert ist.
     * 
     * @param visible
     *            {@code true}: sichtbar, {@code false}: unsichtbar,
     */
    public void setTableActionVisibility(String id, boolean visible) {
        presenter.setTableActionVisibility(id, visible);
    }

    public void download(Download download) {
        presenter.download(download);
    }

    /**
     * @param exportCallback
     *            Callback im Kontext bestimmter Container-Anpassungen.
     */
    public void withExportSettings(ExportWithExportSettings exportCallback) {
        container.withExportSettings(exportCallback);
    }

    /**
     * {@inheritDoc}
     * 
     * @since 1.45
     */
    @Override
    public int getExpandRatio() {
        return config.getExpandRatio() == null ? 1 : config.getExpandRatio();
    }

    /**
     * @return the current edit mode
     */
    public Mode getMode() {
        if (mode == null) {
            // lazy initialize mode for easier testing
            mode = directEdit && isEditable() ? Mode.EDIT : Mode.VIEW;
        }
        return mode;
    }

    /**
     * @return the current display mode
     */
    public DisplayMode getDisplayMode() {
        return displayMode;
    }

    public DataStream getStream() {
        DataStream stream = container.getStream();
        if (columns != null) {
            stream = new GeneratedColumnsDataStreamWrapper(stream, container.getColumns(), columns);
        }
        return stream;
    }

    /**
     * Revert changes made in editing mode
     */
    public void revertChanges() {
        presenter.revertChanges();
    }

    public void setRowValidator(Validator rowValidator) {
        this.rowValidator = rowValidator;
    }

    public boolean hasRowValidator() {
        return rowValidator != null;
    }

    public SelectionMode getSelectionMode() {
        return selectionMode;
    }

}