blob: 16afc16025d0968f8646dee2023afecf8c668c25 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2020 Original authors and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Original authors and others - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.examples.examples._103_Events;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.blink.BlinkConfigAttributes;
import org.eclipse.nebula.widgets.nattable.blink.BlinkLayer;
import org.eclipse.nebula.widgets.nattable.blink.BlinkingCellResolver;
import org.eclipse.nebula.widgets.nattable.blink.IBlinkingCellResolver;
import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes;
import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
import org.eclipse.nebula.widgets.nattable.data.IColumnPropertyAccessor;
import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
import org.eclipse.nebula.widgets.nattable.data.IRowIdAccessor;
import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;
import org.eclipse.nebula.widgets.nattable.examples.AbstractNatExample;
import org.eclipse.nebula.widgets.nattable.examples.runner.StandaloneNatExampleRunner;
import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsEventLayer;
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultRowHeaderDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultColumnHeaderDataLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultGridLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer;
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.style.Style;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.ObservableElementList;
/*
* This is a work in progress while seeking best solution and is therefore
* unlikely to be a good reference example yet...
*/
public class BlinkingGlazedListExample extends AbstractNatExample {
public static void main(String[] args) {
StandaloneNatExampleRunner.run(800, 400,
new BlinkingGlazedListExample());
}
private static final String BLINK_UP_CONFIG_LABEL = "blinkUpConfigLabel";
private static final String BLINK_DOWN_CONFIG_LABEL = "blinkDownConfigLabel";
private final Timer timer = new Timer();
private final EventList<Tuple> baseTupleList;
private final List<String> headers = new ArrayList<>();
private final BasicEventList<Tuple> eventList;
public BlinkingGlazedListExample() {
this.headers.add("Name");
this.headers.add("Value");
this.headers.add("Price");
this.headers.add("Quantity");
this.eventList = new BasicEventList<>();
this.baseTupleList = GlazedLists.threadSafeList(this.eventList);
}
@Override
public String getDescription() {
return "Cell blinking";
}
@Override
public Control createExampleControl(Composite parent) {
// Data backing the table
this.baseTupleList.add(new Tuple(this.headers, new Object[] { "Name 1",
"Value 1", 1.5d, -1000 }, 0));
this.baseTupleList.add(new Tuple(this.headers, new Object[] { "Name 2",
"Value 2", -2.5d, 2000 }, 1));
this.baseTupleList.add(new Tuple(this.headers, new Object[] { "Name 3",
"Value 3", 3.5d, -3000 }, 2));
this.baseTupleList.add(new Tuple(this.headers, new Object[] { "Name 4",
"Value 4", -4.5d, 4000 }, 3));
this.baseTupleList.add(new Tuple(this.headers, new Object[] { "Name 5",
"Value 5", 5.5d, -5000 }, 4));
ConfigRegistry configRegistry = new ConfigRegistry();
ObservableElementList<Tuple> observableTupleList = new ObservableElementList<>(
this.baseTupleList, GlazedLists.beanConnector(Tuple.class));
TupleColumnPropertyAccessor columnPropertyAccessor = new TupleColumnPropertyAccessor();
ListDataProvider<Tuple> bodyDataProvider = new ListDataProvider<>(
observableTupleList, columnPropertyAccessor);
DataLayer bodyDataLayer = new DataLayer(bodyDataProvider);
// Enable capturing glazed list update events
GlazedListsEventLayer<Tuple> glazedListEventsLayer = new GlazedListsEventLayer<>(
bodyDataLayer, this.baseTupleList);
// Enable blinking
final BlinkLayer<Tuple> blinkingLayer = new BlinkLayer<>(
glazedListEventsLayer, bodyDataProvider, getRowIdAccessor(),
columnPropertyAccessor, configRegistry);
registerBlinkingConfigCells(configRegistry);
// Add Listener to existing elements
try {
this.baseTupleList.getReadWriteLock().readLock().lock();
for (Tuple tuple : this.baseTupleList) {
tuple.addPropertyChangeListener(glazedListEventsLayer);
}
} finally {
this.baseTupleList.getReadWriteLock().readLock().unlock();
}
// Setup row/column and corner layers
ColumnHeaderDataProvider defaultColumnHeaderDataProvider = new ColumnHeaderDataProvider();
DefaultRowHeaderDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(
bodyDataProvider);
DefaultCornerDataProvider defaultCornerDataProvider = new DefaultCornerDataProvider(
defaultColumnHeaderDataProvider, rowHeaderDataProvider);
// Build composite for all regions
DefaultGridLayer gridLayer = new DefaultGridLayer(blinkingLayer,
new DefaultColumnHeaderDataLayer(
defaultColumnHeaderDataProvider),
new DefaultRowHeaderDataLayer(rowHeaderDataProvider),
new DataLayer(defaultCornerDataProvider));
NatTable natTable = new NatTable(parent, gridLayer, false);
natTable.setConfigRegistry(configRegistry);
natTable.addConfiguration(new DefaultNatTableStyleConfiguration());
natTable.configure();
return natTable;
}
private IRowIdAccessor<Tuple> getRowIdAccessor() {
return new IRowIdAccessor<Tuple>() {
@Override
public Serializable getRowId(Tuple rowObject) {
return rowObject.id;
}
};
}
@Override
public void onStart() {
this.timer.schedule(new UpdateTupleTask(), 500L, 2000L);
}
@Override
public void onStop() {
this.timer.cancel();
}
public class Tuple implements Comparable<Tuple> {
private final Object[] objects;
private final List<String> propertyNames;
private final long id;
private final PropertyChangeSupport support;
public Tuple(List<String> propertyNames, Object[] objects, long id) {
this.propertyNames = propertyNames;
this.objects = objects;
this.id = id;
this.support = new PropertyChangeSupport(this);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.support.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
this.support.removePropertyChangeListener(listener);
}
public Object getValue(int index) {
return this.objects[index];
}
public void update(int index, Object newValue) {
Object oldValue = this.objects[index];
this.objects[index] = newValue;
System.out.println("Update: " + newValue);
this.support.firePropertyChange(this.propertyNames.get(index), oldValue,
newValue);
}
@Override
public int compareTo(Tuple o) {
return 0;
}
}
private void registerBlinkingConfigCells(ConfigRegistry configRegistry) {
configRegistry.registerConfigAttribute(
BlinkConfigAttributes.BLINK_RESOLVER, getBlinkResolver(),
DisplayMode.NORMAL);
// Styles
Style cellStyle = new Style();
cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR,
Display.getDefault().getSystemColor(SWT.COLOR_GREEN));
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE,
cellStyle, DisplayMode.NORMAL, BLINK_UP_CONFIG_LABEL);
cellStyle = new Style();
cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR,
Display.getDefault().getSystemColor(SWT.COLOR_RED));
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE,
cellStyle, DisplayMode.NORMAL, BLINK_DOWN_CONFIG_LABEL);
}
private IBlinkingCellResolver getBlinkResolver() {
return new BlinkingCellResolver() {
private final String[] configLabels = new String[1];
@Override
public String[] resolve(Object oldValue, Object newValue) {
int old = ((Integer) oldValue).intValue();
int latest = ((Integer) newValue).intValue();
this.configLabels[0] = (latest > old ? BLINK_UP_CONFIG_LABEL
: BLINK_DOWN_CONFIG_LABEL);
return this.configLabels;
};
};
}
public class TupleColumnPropertyAccessor implements
IColumnPropertyAccessor<Tuple> {
@Override
public int getColumnCount() {
return BlinkingGlazedListExample.this.headers.size();
}
@Override
public Object getDataValue(Tuple tuple, int colIndex) {
return tuple.getValue(colIndex);
}
@Override
public void setDataValue(Tuple arg0, int arg1, Object arg2) {
// not supported
}
@Override
public int getColumnIndex(String propertyName) {
return BlinkingGlazedListExample.this.headers.indexOf(propertyName);
}
@Override
public String getColumnProperty(int columnIndex) {
return BlinkingGlazedListExample.this.headers.get(columnIndex);
}
}
public class ColumnHeaderDataProvider implements IDataProvider {
@Override
public int getColumnCount() {
return BlinkingGlazedListExample.this.headers.size();
}
@Override
public Object getDataValue(int columnIndex, int rowIndex) {
return BlinkingGlazedListExample.this.headers.get(columnIndex);
}
@Override
public int getRowCount() {
return 1;
}
@Override
public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
// none
}
}
public class UpdateTupleTask extends TimerTask {
@Override
public void run() {
Tuple toUpdate = BlinkingGlazedListExample.this.baseTupleList.get(2);
Integer existingValue = (Integer) toUpdate.getValue(3);
toUpdate.update(3, existingValue * -1);
}
}
}