import org.eclipse.core.runtime.Platform;\r
import org.eclipse.core.runtime.Status;\r
import org.eclipse.core.runtime.jobs.Job;\r
-import org.eclipse.jface.layout.GridDataFactory;\r
-import org.eclipse.jface.layout.TreeColumnLayout;\r
import org.eclipse.jface.resource.ColorDescriptor;\r
import org.eclipse.jface.resource.DeviceResourceException;\r
import org.eclipse.jface.resource.DeviceResourceManager;\r
import org.eclipse.nebula.widgets.nattable.data.IDataProvider;\r
import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;\r
import org.eclipse.nebula.widgets.nattable.data.convert.DefaultDisplayConverter;\r
+import org.eclipse.nebula.widgets.nattable.data.validate.IDataValidator;\r
+import org.eclipse.nebula.widgets.nattable.data.validate.ValidationFailedException;\r
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;\r
import org.eclipse.nebula.widgets.nattable.edit.EditConfigHelper;\r
import org.eclipse.nebula.widgets.nattable.edit.ICellEditHandler;\r
-import org.eclipse.nebula.widgets.nattable.edit.config.DefaultEditBindings;\r
import org.eclipse.nebula.widgets.nattable.edit.config.DefaultEditConfiguration;\r
+import org.eclipse.nebula.widgets.nattable.edit.config.DialogErrorHandling;\r
import org.eclipse.nebula.widgets.nattable.edit.editor.AbstractCellEditor;\r
import org.eclipse.nebula.widgets.nattable.edit.editor.ComboBoxCellEditor;\r
import org.eclipse.nebula.widgets.nattable.edit.editor.ICellEditor;\r
import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnOverrideLabelAccumulator;\r
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;\r
import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;\r
-import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;\r
+import org.eclipse.nebula.widgets.nattable.painter.NatTableBorderOverlayPainter;\r
import org.eclipse.nebula.widgets.nattable.reorder.ColumnReorderLayer;\r
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;\r
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum;\r
+import org.eclipse.nebula.widgets.nattable.selection.command.SelectCellCommand;\r
import org.eclipse.nebula.widgets.nattable.sort.config.SingleClickSortConfiguration;\r
+import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes;\r
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;\r
+import org.eclipse.nebula.widgets.nattable.style.Style;\r
import org.eclipse.nebula.widgets.nattable.ui.menu.AbstractHeaderMenuConfiguration;\r
import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuBuilder;\r
+import org.eclipse.nebula.widgets.nattable.util.GUIHelper;\r
import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;\r
import org.eclipse.nebula.widgets.nattable.widget.EditModeEnum;\r
import org.eclipse.swt.SWT;\r
import org.eclipse.swt.events.MouseListener;\r
import org.eclipse.swt.events.SelectionListener;\r
import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.graphics.GC;\r
import org.eclipse.swt.graphics.Point;\r
import org.eclipse.swt.graphics.RGB;\r
import org.eclipse.swt.graphics.Rectangle;\r
import gnu.trove.map.hash.TObjectIntHashMap;\r
\r
/**\r
- * NatTable base GraphExplorer\r
+ * NatTable based GraphExplorer\r
+ * \r
+ * This GraphExplorer is not fully compatible with the other implementations, since it is not based on SWT.Tree. \r
+ * \r
+ * This implementation is useful in scenarios, where there are a lot of data to be displayed, the performance of NatTable is much better to SWT.Tree based implementations.\r
* \r
* \r
- * FIXME : asynchronous node loading does not work properly + check expanded/collapsed sate handling\r
- * TODO: InputValidators + input errors\r
* TODO: ability to hide headers\r
* TODO: code cleanup (copied from GraphExplorerImpl2) \r
* \r
*\r
*/\r
public class NatTableGraphExplorer extends GraphExplorerImplBase implements GraphExplorer{\r
- public static final int DEFAULT_MAX_CHILDREN = 1000;\r
+ public static final int DEFAULT_MAX_CHILDREN = 10000;\r
private static final boolean DEBUG_SELECTION_LISTENERS = false;\r
private static final boolean DEBUG = false;\r
\r
originalFont = JFaceResources.getDefaultFontDescriptor();\r
\r
columns = new Column[0];\r
- createNatTable();\r
+ createNatTable(style);\r
layout = new NatTableColumnLayout(natTable, columnHeaderDataProvider, rowHeaderDataLayer);\r
this.composite.setLayout(layout);\r
\r
//refreshColumnSizes();\r
rootNode = new TreeNode(rootContext, explorerContext);\r
if (DEBUG) System.out.println("setRoot " + rootNode);\r
- \r
- // viewer.setInput(rootNode);\r
\r
// Delay content reading.\r
\r
public void run() {\r
if (rootNode != null) {\r
rootNode.updateChildren();\r
+ rootNode.setExpanded(true);\r
listReIndex();\r
- natTable.refresh(true);\r
}\r
}\r
});\r
}\r
\r
private synchronized void listReIndex() {\r
+ for (TreeNode n : list) {\r
+ n.setListIndex(-2);\r
+ }\r
list.clear();\r
for (TreeNode c : rootNode.getChildren())\r
_insertToList(c);\r
+ natTable.refresh();\r
}\r
\r
private void _insertToList(TreeNode n) {\r
}\r
}\r
\r
+ public List<TreeNode> getItems() {\r
+ return Collections.unmodifiableList(list);\r
+ }\r
+ \r
private void initializeState() {\r
if (persistor == null)\r
return;\r
if (natTable.isDisposed())\r
return;\r
doSetColumns(columns, callback);\r
- natTable.refresh(true);\r
+ natTable.refresh();\r
natTable.getParent().layout();\r
}\r
});\r
\r
}\r
\r
+ public boolean select(TreeNode node) {\r
+ assertNotDisposed();\r
+\r
+ if (!list.contains(node)) {\r
+ StructuredSelection s = new StructuredSelection();\r
+ selectionAdaptor.setSelection(s);\r
+ selectionProvider.setAndFireNonEqualSelection(s);\r
+ return true;\r
+ }\r
+ selectionAdaptor.setSelection(new StructuredSelection(node));\r
+ return false;\r
+ }\r
+ \r
+ public void show(TreeNode node) {\r
+ int index = node.getListIndex();\r
+ \r
+ int position = treeLayer.getRowPositionByIndex(index);\r
+ if (position < 0) {\r
+ treeLayer.expandToTreeRow(index);\r
+ position = treeLayer.getRowPositionByIndex(index);\r
+ }\r
+ viewportLayer.moveRowPositionIntoViewport(position);\r
+ }\r
+ \r
@Override\r
public boolean selectPath(Collection<NodeContext> contexts) {\r
\r
else\r
treeLayer.collapseTreeRow(n.getListIndex());\r
}\r
- //viewer.setExpandedState(context, expanded);\r
\r
}\r
\r
public void setAutoExpandLevel(int level) {\r
this.autoExpandLevel = level;\r
treeLayer.expandAllToLevel(level);\r
- //viewer.setAutoExpandLevel(level);\r
}\r
\r
int maxChildren = DEFAULT_MAX_CHILDREN;\r
if (element.isDisposed()) {\r
return;\r
}\r
- if (((TreeNode)element).updateChildren()) {\r
+ if (element.updateChildren()) {\r
+ if (DEBUG) {\r
+ System.out.println("Update Item updateChildren " + element.listIndex + " " + element);\r
+ printDebug(NatTableGraphExplorer.this);\r
+ }\r
listReIndex();\r
- natTable.refresh(true);\r
- //viewer.refresh(element,true);\r
+ if (!element.isHidden()) { \r
+ if (!element.isExpanded()) {\r
+ if (element.listIndex >= 0)\r
+ treeLayer.collapseTreeRow(element.listIndex);\r
+ if (DEBUG) {\r
+ System.out.println("Update Item collapse " + element.listIndex);\r
+ printDebug(NatTableGraphExplorer.this);\r
+ }\r
+ } else {\r
+ for (TreeNode c : element.getChildren())\r
+ c.initData();\r
+ }\r
+ } else {\r
+ TreeNode p = element.getCollapsedAncestor();\r
+ if (p != null) {\r
+ if (element.listIndex >= 0)\r
+ treeLayer.collapseTreeRow(element.listIndex);\r
+ if (p.listIndex >= 0) \r
+ treeLayer.collapseTreeRow(p.listIndex);\r
+ if (DEBUG) {\r
+ System.out.println("Update Item ancetor collapse " + p.listIndex);\r
+ printDebug(NatTableGraphExplorer.this);\r
+ }\r
+ }\r
+ }\r
} else {\r
- if (columnIndex >= 0) {\r
- natTable.redraw();\r
- //viewer.update(element, new String[]{columns[columnIndex].getKey()});\r
- } else {\r
- natTable.redraw();\r
- //viewer.refresh(element,true);\r
- }\r
+// if (columnIndex >= 0) {\r
+// viewer.update(element, new String[]{columns[columnIndex].getKey()});\r
+// } else {\r
+// viewer.refresh(element,true);\r
+// }\r
+ natTable.redraw();\r
}\r
\r
- if (!element.isDisposed() && autoExpandLevel > 1 && !element.isExpanded() && element.getDepth() <= autoExpandLevel) {\r
+ if (!element.autoExpanded && !element.isDisposed() && autoExpandLevel > 1 && !element.isExpanded() && element.getDepth() <= autoExpandLevel) {\r
expand = true;\r
+ element.autoExpanded = true;\r
+ element.initData();\r
+ if (DEBUG) System.out.println("Update Item expand " + element.listIndex);\r
treeLayer.expandTreeRow(element.getListIndex());\r
//viewer.setExpandedState(element, true);\r
expand = false;\r
} else {\r
if (rootNode.updateChildren()) {\r
listReIndex();\r
- natTable.refresh(true);\r
- //viewer.refresh(rootNode,true);\r
}\r
}\r
}\r
}\r
\r
private void update(final TreeNode element, final int columnIndex) {\r
- if (DEBUG)System.out.println("update " + element + " " + columnIndex);\r
if (natTable.isDisposed())\r
return;\r
+ if (element != null && element.isDisposed())\r
+ return;\r
+ if (DEBUG) System.out.println("update " + element + " " + columnIndex);\r
synchronized (pendingItems) {\r
- pendingItems.add(new UpdateItem(element, columnIndex));\r
+ pendingItems.add(new UpdateItem(element, columnIndex));\r
if (updating) return;\r
updateCounter++;\r
scheduleUpdater();\r
}\r
\r
private void update(final TreeNode element) {\r
- if (DEBUG)System.out.println("update " + element);\r
+ \r
if (natTable.isDisposed())\r
return;\r
if (element != null && element.isDisposed())\r
return;\r
+ if (DEBUG) System.out.println("update " + element);\r
synchronized (pendingItems) {\r
- \r
- pendingItems.add(new UpdateItem(element));\r
+ pendingItems.add(new UpdateItem(element));\r
if (updating) return;\r
updateCounter++;\r
scheduleUpdater();\r
return (double)dpi.x/96.0;\r
}\r
\r
- private void createNatTable() {\r
+ private void createNatTable(int style) {\r
GETreeData treeData = new GETreeData(list);\r
GETreeRowModel<TreeNode> treeRowModel = new GETreeRowModel<TreeNode>(treeData);\r
columnAccessor = new GEColumnAccessor(this);\r
natTable.addConfiguration(new SingleClickSortConfiguration());\r
//natTable.addLayerListener(this);\r
\r
- natTable.addConfiguration(new GENatTableThemeConfiguration(treeData));\r
+ natTable.addConfiguration(new GENatTableThemeConfiguration(treeData, style));\r
natTable.addConfiguration(new NatTableHeaderMenuConfiguration(natTable));\r
\r
natTable.addConfiguration(new AbstractRegistryConfiguration() {\r
\r
});\r
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new AdaptableCellEditor());\r
+ configRegistry.registerConfigAttribute(EditConfigAttributes.CONVERSION_ERROR_HANDLER, new DialogErrorHandling(), DisplayMode.EDIT);\r
+ configRegistry.registerConfigAttribute(EditConfigAttributes.VALIDATION_ERROR_HANDLER, new DialogErrorHandling(), DisplayMode.EDIT);\r
+ configRegistry.registerConfigAttribute(EditConfigAttributes.DATA_VALIDATOR, new AdaptableDataValidator(),DisplayMode.EDIT);\r
+ \r
+ Style conversionErrorStyle = new Style();\r
+ conversionErrorStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.COLOR_RED);\r
+ conversionErrorStyle.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR, GUIHelper.COLOR_WHITE);\r
+ configRegistry.registerConfigAttribute(EditConfigAttributes.CONVERSION_ERROR_STYLE, conversionErrorStyle, DisplayMode.EDIT);\r
+ \r
configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER, new DefaultDisplayConverter(),DisplayMode.EDIT);\r
- // configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new GECellPainter(),DisplayMode.NORMAL);\r
-\r
- \r
+ \r
+ \r
}\r
});\r
\r
+ if ((style & SWT.BORDER) > 0) {\r
+ natTable.addOverlayPainter(new NatTableBorderOverlayPainter());\r
+ }\r
+ \r
natTable.configure();\r
\r
// natTable.addListener(SWT.MenuDetect, new NatTableMenuListener());\r
public Rectangle calculateControlBounds(Rectangle cellBounds) {\r
return editor.calculateControlBounds(cellBounds);\r
}\r
+ }\r
+ \r
+ private class AdaptableDataValidator implements IDataValidator {\r
+ @Override\r
+ public boolean validate(ILayerCell cell, IConfigRegistry configRegistry, Object newValue) {\r
+ int col = cell.getColumnIndex();\r
+ int row = cell.getRowIndex();\r
+ return validate(col, row, newValue);\r
+ }\r
\r
- \r
+ @Override\r
+ public boolean validate(int col, int row, Object newValue) {\r
+ TreeNode node = list.get(row);\r
+ Modifier modifier = getModifier(node, col);\r
+ if (modifier == null)\r
+ return false;\r
+ \r
+ String err = modifier.isValid(newValue.toString());\r
+ if (err == null)\r
+ return true;\r
+ modifier.isValid(newValue.toString());\r
+ throw new ValidationFailedException(err);\r
+ }\r
}\r
\r
private class CustomCellEditor extends AbstractCellEditor {\r
}\r
if (DEBUG) System.out.println("UpdateRunner.doRun() " + items.size());\r
\r
- ge.natTable.setRedraw(false);\r
+ //ge.natTable.setRedraw(false);\r
for (UpdateItem item : items) {\r
item.update(ge.natTable);\r
}\r
ge.natTable.getParent().layout();\r
}\r
\r
- ge.natTable.setRedraw(true);\r
+ //ge.natTable.setRedraw(true);\r
\r
synchronized (ge.pendingItems) {\r
if (!ge.scheduleUpdater()) {\r
}\r
if (DEBUG) {\r
if (!ge.updating) {\r
- ge.printTree(ge.rootNode, 0);\r
+ printDebug(ge); \r
}\r
}\r
}\r
\r
}\r
\r
+ private static void printDebug(NatTableGraphExplorer ge) {\r
+ ge.printTree(ge.rootNode, 0);\r
+ System.out.println("Expanded");\r
+ for (TreeNode n : ge.treeLayer.expanded)\r
+ System.out.println(n);\r
+ System.out.println("Expanded end");\r
+ System.out.println("Hidden ");\r
+ for (int i : ge.treeLayer.getHiddenRowIndexes()) {\r
+ System.out.print(i + " ");\r
+ }\r
+ System.out.println();\r
+// Display.getCurrent().timerExec(1000, new Runnable() {\r
+// \r
+// @Override\r
+// public void run() {\r
+// System.out.println("Hidden delayed ");\r
+// for (int i : ge.treeLayer.getHiddenRowIndexes()) {\r
+// System.out.print(i + " ");\r
+// }\r
+// System.out.println();\r
+// }\r
+// });\r
+ }\r
\r
\r
public static class GeViewerContext extends AbstractDisposable implements IGraphExplorerContext {\r
\r
@Override\r
public void handleLayerEvent(ILayerEvent event) {\r
- // TODO Auto-generated method stub\r
if (event instanceof ShowRowPositionsEvent) {\r
ShowRowPositionsEvent e = (ShowRowPositionsEvent)event;\r
for (Range r : e.getRowPositionRanges()) {\r
int expanded = viewportLayer.getRowIndexByPosition(r.start-2)+1;\r
- //System.out.println("ex " + expanded);\r
- if (expanded < 0) {\r
+ if (DEBUG)System.out.println("IsExpandedProcessor expand " + expanded);\r
+ if (expanded < 0 || expanded >= list.size()) {\r
return;\r
}\r
- nodeStatusChanged(list.get(expanded).getContext(), false);\r
+ nodeStatusChanged(list.get(expanded).getContext(), true);\r
}\r
} else if (event instanceof HideRowPositionsEvent) {\r
HideRowPositionsEvent e = (HideRowPositionsEvent)event;\r
for (Range r : e.getRowPositionRanges()) {\r
- int collapsed = viewportLayer.getRowIndexByPosition(r.start-2)+1;\r
- //System.out.println("col " + collapsed);\r
- if (collapsed < 0) {\r
+ int collapsed = viewportLayer.getRowIndexByPosition(r.start-2);\r
+ if (DEBUG)System.out.println("IsExpandedProcessor collapse " + collapsed);\r
+ if (collapsed < 0 || collapsed >= list.size()) {\r
return;\r
}\r
nodeStatusChanged(list.get(collapsed).getContext(), false);\r
}\r
}\r
\r
-private class NatTableHeaderMenuConfiguration extends AbstractHeaderMenuConfiguration {\r
+ private class NatTableHeaderMenuConfiguration extends AbstractHeaderMenuConfiguration {\r
\r
\r
public NatTableHeaderMenuConfiguration(NatTable natTable) {\r
Point point = new Point(e.x, e.y);\r
int y = natTable.getRowPositionByY(point.y);\r
int x = natTable.getColumnPositionByX(point.x);\r
- if (x < 0 | y < 0)\r
+ if (x < 0 | y <= 0)\r
return null;\r
- return list.get(y); \r
+ return list.get(y-1); \r
}\r
}\r