Java tutorial
/******************************************************************************* * Copyright (c) 2012, 2013 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); } } } }); } } }