blob: 4a19ee2222ad4cc37391d4a7130f3adf2d52cca6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 Original authors and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Original authors and others - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.examples.examples;
import static org.eclipse.nebula.widgets.nattable.util.ObjectUtils.isNotNull;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.math.RandomUtils;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.blink.BlinkConfigAttributes;
import org.eclipse.nebula.widgets.nattable.blink.BlinkingCellResolver;
import org.eclipse.nebula.widgets.nattable.blink.IBlinkingCellResolver;
import org.eclipse.nebula.widgets.nattable.columnChooser.command.DisplayColumnChooserCommandHandler;
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.ListDataProvider;
import org.eclipse.nebula.widgets.nattable.examples.AbstractNatExample;
import org.eclipse.nebula.widgets.nattable.examples.PersistentNatExampleWrapper;
import org.eclipse.nebula.widgets.nattable.examples.examples._110_Editing.EditableGridExample;
import org.eclipse.nebula.widgets.nattable.examples.examples._131_Filtering.FilterRowGridExample;
import org.eclipse.nebula.widgets.nattable.examples.examples._150_Column_and_row_grouping._300_Summary_row;
import org.eclipse.nebula.widgets.nattable.examples.fixtures.FullFeaturedBodyLayerStack;
import org.eclipse.nebula.widgets.nattable.examples.fixtures.FullFeaturedColumnHeaderLayerStack;
import org.eclipse.nebula.widgets.nattable.examples.runner.StandaloneNatExampleRunner;
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.data.DefaultSummaryRowHeaderDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer;
import org.eclipse.nebula.widgets.nattable.group.ColumnGroupModel;
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnOverrideLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.sort.config.SingleClickSortConfiguration;
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.nebula.widgets.nattable.test.fixture.data.BlinkingRowDataFixture;
import org.eclipse.nebula.widgets.nattable.test.fixture.data.RowDataListFixture;
import org.eclipse.nebula.widgets.nattable.ui.menu.HeaderMenuConfiguration;
import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuBuilder;
import org.eclipse.nebula.widgets.nattable.util.GUIHelper;
import org.eclipse.nebula.widgets.nattable.widget.WaitDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.FilterList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.ObservableElementList;
import ca.odell.glazedlists.SortedList;
public class _900_Everything_but_the_kitchen_sink extends AbstractNatExample {
public static void main(String[] args) {
StandaloneNatExampleRunner.run(1000, 800, new PersistentNatExampleWrapper(new _900_Everything_but_the_kitchen_sink()));
}
@Override
public String getDescription() {
return "The example with everything. Well, not quite everything, but a lot.";
}
private static final String BLINK_UP_CONFIG_LABEL = "blinkUpConfigLabel";
private static final String BLINK_DOWN_CONFIG_LABEL = "blinkDownConfigLabel";
private EventList<BlinkingRowDataFixture> baseEventList;
private PropertyChangeListener propertyChangeListener;
private ListDataProvider<BlinkingRowDataFixture> bodyDataProvider;
private NatTable natTable;
private ScheduledExecutorService scheduledThreadPool;
public Control createExampleControl(Composite parent) {
final String[] propertyNames = RowDataListFixture.getPropertyNames();
final Map<String, String> propertyToLabelMap = RowDataListFixture.getPropertyToLabelMap();
ConfigRegistry configRegistry = new ConfigRegistry();
ColumnGroupModel columnGroupModel = new ColumnGroupModel();
// Body
LinkedList<BlinkingRowDataFixture> rowData = new LinkedList<BlinkingRowDataFixture>();
baseEventList = GlazedLists.threadSafeList(GlazedLists.eventList(rowData));
ObservableElementList<BlinkingRowDataFixture> observableElementList = new ObservableElementList<BlinkingRowDataFixture>(
baseEventList, GlazedLists.beanConnector(BlinkingRowDataFixture.class));
FilterList<BlinkingRowDataFixture> filterList = new FilterList<BlinkingRowDataFixture>(observableElementList);
SortedList<BlinkingRowDataFixture> sortedList = new SortedList<BlinkingRowDataFixture>(filterList, null);
FullFeaturedBodyLayerStack<BlinkingRowDataFixture> bodyLayer =
new FullFeaturedBodyLayerStack<BlinkingRowDataFixture>(
sortedList,
BlinkingRowDataFixture.rowIdAccessor,
propertyNames,
configRegistry,
columnGroupModel);
bodyDataProvider = bodyLayer.getBodyDataProvider();
propertyChangeListener = bodyLayer.getGlazedListEventsLayer();
// blinking
registerBlinkingConfigCells(configRegistry);
// Column header
FullFeaturedColumnHeaderLayerStack<BlinkingRowDataFixture> columnHeaderLayer =
new FullFeaturedColumnHeaderLayerStack<BlinkingRowDataFixture>(
sortedList,
filterList,
propertyNames,
propertyToLabelMap,
bodyLayer,
bodyLayer.getSelectionLayer(),
columnGroupModel,
configRegistry);
// column groups
setUpColumnGroups(columnHeaderLayer);
// Row header
final DefaultRowHeaderDataProvider rowHeaderDataProvider = new DefaultSummaryRowHeaderDataProvider(bodyDataProvider);
DefaultRowHeaderDataLayer rowHeaderDataLayer = new DefaultRowHeaderDataLayer(rowHeaderDataProvider);
rowHeaderDataLayer.setDefaultColumnWidth(50);
ILayer rowHeaderLayer = new RowHeaderLayer(rowHeaderDataLayer, bodyLayer, bodyLayer.getSelectionLayer());
// Corner
final DefaultCornerDataProvider cornerDataProvider = new DefaultCornerDataProvider(columnHeaderLayer.getColumnHeaderDataProvider(), rowHeaderDataProvider);
DataLayer cornerDataLayer = new DataLayer(cornerDataProvider);
ILayer cornerLayer = new CornerLayer(cornerDataLayer, rowHeaderLayer, columnHeaderLayer);
// Grid
GridLayer gridLayer = new GridLayer(
bodyLayer,
columnHeaderLayer,
rowHeaderLayer,
cornerLayer
);
natTable = new NatTable(parent, gridLayer, false);
natTable.setConfigRegistry(configRegistry);
natTable.addConfiguration(new DefaultNatTableStyleConfiguration());
// Popup menu
natTable.addConfiguration(new HeaderMenuConfiguration(natTable) {
@Override
protected PopupMenuBuilder createColumnHeaderMenu(NatTable natTable) {
return super.createColumnHeaderMenu(natTable).withColumnChooserMenuItem();
}
});
natTable.addConfiguration(new SingleClickSortConfiguration());
// Editing
ColumnOverrideLabelAccumulator columnLabelAccumulator = new ColumnOverrideLabelAccumulator(bodyLayer.getBodyDataLayer());
bodyLayer.getBodyDataLayer().setConfigLabelAccumulator(columnLabelAccumulator);
natTable.addConfiguration(EditableGridExample.editableGridConfiguration(columnLabelAccumulator, bodyDataProvider));
natTable.addConfiguration(new FilterRowGridExample.FilterRowCustomConfiguration());
// Column chooser
DisplayColumnChooserCommandHandler columnChooserCommandHandler = new DisplayColumnChooserCommandHandler(
bodyLayer.getSelectionLayer(),
bodyLayer.getColumnHideShowLayer(),
columnHeaderLayer.getColumnHeaderLayer(),
columnHeaderLayer.getColumnHeaderDataLayer(),
columnHeaderLayer.getColumnGroupHeaderLayer(),
columnGroupModel);
bodyLayer.registerCommandHandler(columnChooserCommandHandler);
// Summary row configuration
natTable.addConfiguration(new _300_Summary_row<BlinkingRowDataFixture>(bodyDataProvider));
natTable.configure();
return natTable;
}
private void setUpColumnGroups(FullFeaturedColumnHeaderLayerStack<BlinkingRowDataFixture> headerLayer) {
headerLayer.getColumnGroupHeaderLayer().addColumnsIndexesToGroup("TestGroup", 1,2);
headerLayer.getColumnGroupHeaderLayer().addColumnsIndexesToGroup("TestGroup1", 5,6,7);
headerLayer.getColumnGroupHeaderLayer().setGroupUnbreakable(5);
headerLayer.getColumnGroupHeaderLayer().setGroupAsCollapsed(5);
}
@Override
public void onStart() {
Display.getDefault().asyncExec( new Runnable() {
public void run() {
scheduledThreadPool = Executors.newScheduledThreadPool(1);
System.out.println("Starting data load.");
scheduledThreadPool.schedule(new DataLoader(propertyChangeListener, baseEventList), 100L, TimeUnit.MILLISECONDS);
scheduledThreadPool.scheduleAtFixedRate(new DataUpdater(bodyDataProvider), 100L, 5000L, TimeUnit.MILLISECONDS);
}
});
}
@Override
public void onStop() {
if (isNotNull(scheduledThreadPool)) {
scheduledThreadPool.shutdownNow();
}
}
private void registerBlinkingConfigCells(ConfigRegistry configRegistry) {
configRegistry.registerConfigAttribute(BlinkConfigAttributes.BLINK_RESOLVER, getBlinkResolver(), DisplayMode.NORMAL);
// Styles
Style cellStyle = new Style();
cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.COLOR_GREEN);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, cellStyle, DisplayMode.NORMAL, BLINK_UP_CONFIG_LABEL);
cellStyle = new Style();
cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.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];
public String[] resolve(Object oldValue, Object newValue) {
double old = ((Double) oldValue).doubleValue();
double latest = ((Double) newValue).doubleValue();
configLabels[0] = (latest > old ? BLINK_UP_CONFIG_LABEL : BLINK_DOWN_CONFIG_LABEL);
return configLabels;
}
};
}
private final Random random = new Random();
private static final int DATASET_SIZE = 52000;
/**
* Initial data load. Loads data in batches.
*
* Note: It is a significantly more efficient to do the load in batches
* i.e using {@link List#addAll(java.util.Collection)} instead of adding objects
* individually.
*
* @See https://sourceforge.net/projects/nattable/forums/forum/744994/topic/3410065
*/
class DataLoader implements Runnable {
private final PropertyChangeListener changeListener;
private final EventList<BlinkingRowDataFixture> list;
private final String waitMsg = "Loading data. Please wait... ";
private WaitDialog dialog;
public DataLoader(PropertyChangeListener changeListener, EventList<BlinkingRowDataFixture> baseEventList) {
this.changeListener = changeListener;
this.list = baseEventList;
}
public void run() {
try {
// Display wait dialog
Display.getDefault().asyncExec(new Runnable() {
public void run() {
final Image icon = new Image(Display.getDefault(), getClass().getResourceAsStream("waiting.gif"));
dialog = new WaitDialog(natTable.getShell(), SWT.NONE, waitMsg, icon);
dialog.setBlockOnOpen(true);
dialog.open();
}
});
// Load data
while(list.size() < DATASET_SIZE){
// Add to buffer
List<BlinkingRowDataFixture> buffer = new ArrayList<BlinkingRowDataFixture>();
for (int i = 0; i < 100; i++) {
buffer.addAll(BlinkingRowDataFixture.getList(changeListener));
}
// Load as a batch
list.addAll(buffer);
// Update wait dialog
Display.getDefault().syncExec(new Runnable() {
public void run() {
dialog.setMsg(waitMsg + list.size());
}
});
}
// Close wait dialog
Display.getDefault().asyncExec(new Runnable() {
public void run() {
dialog.close();
}
});
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
public Runnable runWithBusyIndicator(final Runnable runnable) {
return new Runnable() {
public void run() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
BusyIndicator.showWhile(Display.getDefault(), runnable);
}
});
}
};
}
/**
* Pumps data updates to drive blinking
*/
class DataUpdater implements Runnable {
ListDataProvider<BlinkingRowDataFixture> dataProvider;
int counter = 0;
DataUpdater(ListDataProvider<BlinkingRowDataFixture> dataProvider) {
this.dataProvider = dataProvider;
}
public void run() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
for (int i = 0; i < 5; i++) {
int index = RandomUtils.nextInt(13);
int nextAsk = random.nextInt(1000);
if (dataProvider.getRowCount() > index) {
BlinkingRowDataFixture rowObject = dataProvider.getRowObject(index);
//System.out.println("Ask: "+rowObject.getAsk_price()+" --> "+nextAsk);
rowObject.setAsk_price(nextAsk);
rowObject.setBid_price(-1 * nextAsk);
}
}
}
});
}
}
}