/*
* Copyright (c) 2011, grossmann, Nikolaus Moll
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the jo-widgets.org nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL jo-widgets.org BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.jowidgets.impl.widgets.basic;
import java.util.ArrayList;
import java.util.List;
import org.jowidgets.api.controller.IDisposeListener;
import org.jowidgets.api.controller.IListSelectionVetoListener;
import org.jowidgets.api.controller.IParentListener;
import org.jowidgets.api.model.table.ITableColumn;
import org.jowidgets.api.model.table.ITableColumnModel;
import org.jowidgets.api.widgets.IContainer;
import org.jowidgets.api.widgets.IPopupMenu;
import org.jowidgets.api.widgets.ITable;
import org.jowidgets.api.widgets.descriptor.setup.ITableSetup;
import org.jowidgets.common.model.ITableDataModel;
import org.jowidgets.common.types.Dimension;
import org.jowidgets.common.types.Position;
import org.jowidgets.common.types.TablePackPolicy;
import org.jowidgets.common.widgets.controller.ITableCellListener;
import org.jowidgets.common.widgets.controller.ITableCellMouseEvent;
import org.jowidgets.common.widgets.controller.ITableCellPopupDetectionListener;
import org.jowidgets.common.widgets.controller.ITableCellPopupEvent;
import org.jowidgets.common.widgets.controller.ITableColumnListener;
import org.jowidgets.common.widgets.controller.ITableColumnMouseEvent;
import org.jowidgets.common.widgets.controller.ITableColumnPopupDetectionListener;
import org.jowidgets.common.widgets.controller.ITableColumnPopupEvent;
import org.jowidgets.common.widgets.controller.ITableColumnResizeEvent;
import org.jowidgets.common.widgets.controller.ITableSelectionListener;
import org.jowidgets.impl.base.delegate.ControlDelegate;
import org.jowidgets.impl.widgets.common.wrapper.AbstractControlSpiWrapper;
import org.jowidgets.spi.widgets.ITableSpi;
import org.jowidgets.tools.controller.ListSelectionVetoObservable;
import org.jowidgets.tools.controller.TableSelectionObservable;
import org.jowidgets.tools.widgets.invoker.ColorSettingsInvoker;
import org.jowidgets.tools.widgets.invoker.VisibiliySettingsInvoker;
import org.jowidgets.util.EmptyCheck;
import org.jowidgets.util.Interval;
import org.jowidgets.util.NullCompatibleEquivalence;
public class TableImpl extends AbstractControlSpiWrapper implements ITable {
private static final TablePackPolicy DEFAULT_PACK_POLICY = TablePackPolicy.HEADER_AND_DATA_VISIBLE;
private final ControlDelegate controlDelegate;
private final ITableDataModel dataModel;
private final ITableColumnModel columnModel;
private final int maxPackWidth;
private final TableCellObservableSpiAdapter cellObservable;
private final TableCellPopupDetectionObservableSpiAdapter cellPopupDetectionObservable;
private final TableColumnObservableSpiAdapter columnObservable;
private final TableColumnPopupDetectionObservableSpiAdapter columnPopupDetectionObservable;
private final TableSelectionObservable tableSelectionObservable;
private final ListSelectionVetoObservable selectionVetoObservable;
private final ITableSelectionListener tableSelectionListener;
private final TableModelSpiAdapter modelSpiAdapter;
private ArrayList<Integer> lastSelection;
public TableImpl(final ITableSpi widgetSpi, final ITableSetup setup, final TableModelSpiAdapter modelSpiAdapter) {
super(widgetSpi);
this.controlDelegate = new ControlDelegate(widgetSpi, this);
this.dataModel = setup.getDataModel();
this.columnModel = setup.getColumnModel();
this.maxPackWidth = setup.getColumnMaxPackWidth();
this.modelSpiAdapter = modelSpiAdapter;
this.cellObservable = new TableCellObservableSpiAdapter();
this.selectionVetoObservable = new ListSelectionVetoObservable();
this.tableSelectionObservable = new TableSelectionObservable();
getWidget().setEditable(setup.isEditable());
getWidget().addTableCellListener(new ITableCellListener() {
@Override
public void mouseReleased(final ITableCellMouseEvent event) {
cellObservable.fireMouseReleased(event, modelSpiAdapter);
}
@Override
public void mousePressed(final ITableCellMouseEvent event) {
cellObservable.fireMousePressed(event, modelSpiAdapter);
}
@Override
public void mouseDoubleClicked(final ITableCellMouseEvent event) {
cellObservable.fireMouseDoubleClicked(event, modelSpiAdapter);
}
});
this.cellPopupDetectionObservable = new TableCellPopupDetectionObservableSpiAdapter();
getWidget().addTableCellPopupDetectionListener(new ITableCellPopupDetectionListener() {
@Override
public void popupDetected(final ITableCellPopupEvent event) {
cellPopupDetectionObservable.firePopupDetected(event, modelSpiAdapter);
}
});
this.columnObservable = new TableColumnObservableSpiAdapter();
getWidget().addTableColumnListener(new ITableColumnListener() {
@Override
public void mouseClicked(final ITableColumnMouseEvent event) {
columnObservable.fireMouseClicked(event, modelSpiAdapter);
}
@Override
public void columnResized(final ITableColumnResizeEvent event) {
columnObservable.fireColumnResized(event, modelSpiAdapter);
}
@Override
public void columnPermutationChanged() {
modelSpiAdapter.tableColumnPermutationChanged(getWidget().getColumnPermutation());
columnObservable.fireColumnPermutationChanged();
}
});
this.columnPopupDetectionObservable = new TableColumnPopupDetectionObservableSpiAdapter();
getWidget().addTableColumnPopupDetectionListener(new ITableColumnPopupDetectionListener() {
@Override
public void popupDetected(final ITableColumnPopupEvent event) {
columnPopupDetectionObservable.firePopupDetected(event, modelSpiAdapter);
}
});
this.tableSelectionListener = new ITableSelectionListener() {
@Override
public void selectionChanged() {
if (NullCompatibleEquivalence.equals(lastSelection, getWidget().getSelection())) {
//ignore selection already set
return;
}
if (selectionVetoObservable.allowSelectionChange(getWidget().getSelection())) {
lastSelection = getWidget().getSelection();
dataModel.setSelection(getSelection());
tableSelectionObservable.fireSelectionChanged();
}
else {
getWidget().removeTableSelectionListener(tableSelectionListener);
try {
getWidget().setSelection(lastSelection);
}
finally {
getWidget().addTableSelectionListener(tableSelectionListener);
}
}
}
};
getWidget().addTableSelectionListener(tableSelectionListener);
VisibiliySettingsInvoker.setVisibility(setup, this);
ColorSettingsInvoker.setColors(setup, this);
resetFromModel();
lastSelection = getWidget().getSelection();
}
@Override
public ITableSpi getWidget() {
return (ITableSpi) super.getWidget();
}
@Override
public IContainer getParent() {
return controlDelegate.getParent();
}
@Override
public void setParent(final IContainer parent) {
controlDelegate.setParent(parent);
}
@Override
public void addParentListener(final IParentListener<IContainer> listener) {
controlDelegate.addParentListener(listener);
}
@Override
public void removeParentListener(final IParentListener<IContainer> listener) {
controlDelegate.removeParentListener(listener);
}
@Override
public boolean isReparentable() {
return controlDelegate.isReparentable();
}
@Override
public void addDisposeListener(final IDisposeListener listener) {
controlDelegate.addDisposeListener(listener);
}
@Override
public void removeDisposeListener(final IDisposeListener listener) {
controlDelegate.removeDisposeListener(listener);
}
@Override
public boolean isDisposed() {
return controlDelegate.isDisposed();
}
@Override
public void dispose() {
controlDelegate.dispose();
}
@Override
public IPopupMenu createPopupMenu() {
return controlDelegate.createPopupMenu();
}
@Override
public int getRowCount() {
return dataModel.getRowCount();
}
@Override
public int getColumnCount() {
return columnModel.getColumnCount();
}
@Override
public boolean editCell(final int row, final int column) {
return getWidget().editCell(row, modelSpiAdapter.convertModelToView(column));
}
@Override
public void stopEditing() {
getWidget().stopEditing();
}
@Override
public void cancelEditing() {
getWidget().cancelEditing();
}
@Override
public boolean isEditing() {
return getWidget().isEditing();
}
@Override
public void resetFromModel() {
getWidget().resetFromModel();
}
@Override
public int convertColumnIndexToView(final int modelIndex) {
final ArrayList<Integer> permutation = getColumnPermutation();
return permutation.indexOf(Integer.valueOf(modelIndex));
}
@Override
public int convertColumnIndexToModel(final int viewIndex) {
return getColumnPermutation().get(viewIndex).intValue();
}
@Override
public void moveColumn(final int oldViewIndex, final int newViewIndex) {
final ArrayList<Integer> permutation = getColumnPermutation();
final int oldPermutationValue = permutation.get(oldViewIndex).intValue();
permutation.remove(oldViewIndex);
permutation.add(newViewIndex, oldPermutationValue);
setColumnPermutation(permutation);
}
@Override
public void pack() {
pack(DEFAULT_PACK_POLICY);
}
@Override
public void pack(final int columnIndex) {
pack(columnIndex, DEFAULT_PACK_POLICY);
}
@Override
public void pack(final TablePackPolicy policy) {
getWidget().pack(policy);
afterPack(null);
}
@Override
public void pack(final int columnIndex, final TablePackPolicy policy) {
final int convertedIndex = modelSpiAdapter.convertModelToView(columnIndex);
getWidget().pack(convertedIndex, policy);
afterPack(columnIndex);
}
private void afterPack(final Integer columnIndex) {
if (columnIndex != null) {
final ITableColumn column = columnModel.getColumn(columnIndex.intValue());
if (column.getWidth() > maxPackWidth) {
column.setWidth(maxPackWidth);
}
}
else {
for (int i = 0; i < getColumnCount(); i++) {
afterPack(Integer.valueOf(i));
}
}
}
@Override
public void resetColumnPermutation() {
final List<Integer> permutation = new ArrayList<Integer>(getColumnCount());
for (int i = 0; i < getColumnCount(); i++) {
permutation.add(Integer.valueOf(i));
}
setColumnPermutation(permutation);
}
@Override
public void setEditable(final boolean editable) {
getWidget().setEditable(editable);
}
@Override
public Position getCellPosition(final int rowIndex, final int columnIndex) {
return getWidget().getCellPosition(rowIndex, modelSpiAdapter.convertModelToView(columnIndex));
}
@Override
public Dimension getCellSize(final int rowIndex, final int columnIndex) {
return getWidget().getCellSize(rowIndex, modelSpiAdapter.convertModelToView(columnIndex));
}
@Override
public int getColumnAtPosition(final Position position) {
final int result = getWidget().getColumnAtPosition(position);
if (result != -1) {
return modelSpiAdapter.convertViewToModel(result);
}
return -1;
}
@Override
public int getRowAtPosition(final Position position) {
return getWidget().getRowAtPosition(position);
}
@Override
public ArrayList<Integer> getColumnPermutation() {
return modelSpiAdapter.getCurrentPermutation();
}
@Override
public void setColumnPermutation(final List<Integer> permutation) {
getWidget().setColumnPermutation(modelSpiAdapter.convertColumnPermutationToView(permutation));
}
@Override
public ArrayList<Integer> getSelection() {
return lastSelection;
}
@Override
public void setSelection(final List<Integer> selection) {
getWidget().setSelection(selection);
}
@Override
public void scrollToSelection() {
final ArrayList<Integer> selection = getSelection();
if (!EmptyCheck.isEmpty(selection)) {
scrollToRow(selection.iterator().next());
}
}
@Override
public void scrollToEnd() {
if (getRowCount() > 0) {
scrollToRow(getRowCount() - 1);
}
}
@Override
public void scrollToRow(final int rowIndex) {
getWidget().scrollToRow(rowIndex);
}
@Override
public boolean isColumnPopupDetectionSupported() {
return getWidget().isColumnPopupDetectionSupported();
}
@Override
public Interval<Integer> getVisibleRows() {
return getWidget().getVisibleRows();
}
@Override
public void addTableCellPopupDetectionListener(final ITableCellPopupDetectionListener listener) {
cellPopupDetectionObservable.addTableCellPopupDetectionListener(listener);
}
@Override
public void removeTableCellPopupDetectionListener(final ITableCellPopupDetectionListener listener) {
cellPopupDetectionObservable.removeTableCellPopupDetectionListener(listener);
}
@Override
public void addTableCellListener(final ITableCellListener listener) {
cellObservable.addTableCellListener(listener);
}
@Override
public void removeTableCellListener(final ITableCellListener listener) {
cellObservable.removeTableCellListener(listener);
}
@Override
public void addTableColumnPopupDetectionListener(final ITableColumnPopupDetectionListener listener) {
columnPopupDetectionObservable.addTableColumnPopupDetectionListener(listener);
}
@Override
public void removeTableColumnPopupDetectionListener(final ITableColumnPopupDetectionListener listener) {
columnPopupDetectionObservable.removeTableColumnPopupDetectionListener(listener);
}
@Override
public void addTableSelectionListener(final ITableSelectionListener listener) {
tableSelectionObservable.addTableSelectionListener(listener);
}
@Override
public void removeTableSelectionListener(final ITableSelectionListener listener) {
tableSelectionObservable.removeTableSelectionListener(listener);
}
@Override
public void addSelectionVetoListener(final IListSelectionVetoListener listener) {
selectionVetoObservable.addSelectionVetoListener(listener);
}
@Override
public void removeSelectionVetoListener(final IListSelectionVetoListener listener) {
selectionVetoObservable.removeSelectionVetoListener(listener);
}
@Override
public void addTableColumnListener(final ITableColumnListener listener) {
columnObservable.addTableColumnListener(listener);
}
@Override
public void removeTableColumnListener(final ITableColumnListener listener) {
columnObservable.removeTableColumnListener(listener);
}
@Override
public void setRowHeight(final int height) {
getWidget().setRowHeight(height);
}
}