package org.simantics.browsing.ui.nattable;\r
\r
+import org.eclipse.core.runtime.FileLocator;\r
+import org.eclipse.core.runtime.Path;\r
+import org.eclipse.nebula.widgets.nattable.painter.cell.BackgroundPainter;\r
import org.eclipse.nebula.widgets.nattable.painter.cell.TextPainter;\r
import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.PaddingDecorator;\r
import org.eclipse.nebula.widgets.nattable.style.theme.ModernNatTableThemeConfiguration;\r
+import org.eclipse.nebula.widgets.nattable.tree.painter.IndentedTreeImagePainter;\r
+import org.eclipse.nebula.widgets.nattable.tree.painter.TreeImagePainter;\r
+import org.eclipse.nebula.widgets.nattable.ui.util.CellEdgeEnum;\r
import org.eclipse.nebula.widgets.nattable.util.GUIHelper;\r
\r
public class GENatTableThemeConfiguration extends ModernNatTableThemeConfiguration{\r
\r
- public GENatTableThemeConfiguration(GETreeData treeData) {\r
+ public GENatTableThemeConfiguration(GETreeData treeData, int style) {\r
super();\r
this.oddRowBgColor = GUIHelper.getColor(250, 250, 250);\r
this.defaultCellPainter =\r
0,\r
5,\r
false)));\r
+ \r
+ TreeImagePainter treeImagePainter =\r
+ new TreeImagePainter(\r
+ false,\r
+ GUIHelper.getImage("right"), //$NON-NLS-1$\r
+ GUIHelper.getImage("right_down"), //$NON-NLS-1$\r
+ GUIHelper.getImageByURL("transparent", \r
+ FileLocator.find(Activator.getDefault().getBundle(), \r
+ new Path("images/transparent.png"), null))); //$NON-NLS-1$\r
+ this.treeStructurePainter =\r
+ new BackgroundPainter(\r
+ new PaddingDecorator(\r
+ new IndentedTreeImagePainter(\r
+ 10,\r
+ null,\r
+ CellEdgeEnum.LEFT,\r
+ treeImagePainter,\r
+ false,\r
+ 2,\r
+ true),\r
+ 0,\r
+ 5,\r
+ 0,\r
+ 5,\r
+ false));\r
+ TreeImagePainter treeSelectionImagePainter =\r
+ new TreeImagePainter(\r
+ false,\r
+ GUIHelper.getImage("right_inv"), //$NON-NLS-1$\r
+ GUIHelper.getImage("right_down_inv"), //$NON-NLS-1$\r
+ GUIHelper.getImageByURL("transparent", \r
+ FileLocator.find(Activator.getDefault().getBundle(), \r
+ new Path("images/transparent.png"), null))); //$NON-NLS-1$\r
+ this.treeStructureSelectionPainter =\r
+ new BackgroundPainter(\r
+ new PaddingDecorator(\r
+ new IndentedTreeImagePainter(\r
+ 10,\r
+ null,\r
+ CellEdgeEnum.LEFT,\r
+ treeSelectionImagePainter,\r
+ false,\r
+ 2,\r
+ true),\r
+ 0,\r
+ 5,\r
+ 0,\r
+ 5,\r
+ false));\r
}\r
\r
}\r
package org.simantics.browsing.ui.nattable;\r
\r
import java.util.ArrayList;\r
-import java.util.Collection;\r
import java.util.Collections;\r
import java.util.Comparator;\r
+import java.util.HashSet;\r
import java.util.Iterator;\r
import java.util.List;\r
import java.util.Set;\r
public class GETreeLayer extends TreeLayer2 {\r
\r
//Set<IEcoReportTask> collapsed = new HashSet<IEcoReportTask>();\r
- Set<TreeNode> collapsed = new IdentityHashSet<TreeNode>();\r
+ Set<TreeNode> expanded = new IdentityHashSet<TreeNode>();\r
GETreeData treeData;\r
Comparator<int[]> comparator = new FirstElementComparator();\r
\r
@Override\r
public void collapseTreeRow(int parentIndex) {\r
TreeNode task = treeData.getDataAtIndex(parentIndex);\r
- collapsed.add(task);\r
+ expanded.remove(task);\r
task.setExpanded(false);\r
super.collapseTreeRow(parentIndex);\r
}\r
@Override\r
public void expandTreeRow(int parentIndex) {\r
TreeNode task = treeData.getDataAtIndex(parentIndex);\r
- collapsed.remove(task);\r
+ expanded.add(task);\r
task.setExpanded(true);\r
super.expandTreeRow(parentIndex);\r
}\r
TreeNode task = treeData.getDataAtIndex(parentIndex);\r
if (task != null) {\r
task.setExpanded(false);\r
- collapsed.add(task);\r
+ expanded.remove(task);\r
}\r
rowIndexes.addAll(getModel().collapse(parentIndex));\r
}\r
if (parentIndex >= 0) {\r
TreeNode task = treeData.getDataAtIndex(parentIndex);\r
task.setExpanded(false);\r
- collapsed.add(task);\r
+ expanded.remove(task);\r
rowIndexes.addAll(getModel().collapse(parentIndex));\r
}\r
}\r
\r
} \r
t.setExpanded(false);\r
- collapsed.add(t);\r
+ expanded.remove(t);\r
getModel().collapse(i);\r
\r
}\r
for (int parentIndex : parentIndices) {\r
TreeNode task = treeData.getDataAtIndex(parentIndex);\r
task.setExpanded(true);\r
- collapsed.remove(task);\r
+ expanded.add(task);\r
rowIndexes.addAll(getModel().expand(parentIndex));\r
+ rowIndexes.add(parentIndex);\r
}\r
\r
//Implementation uses tree set, so removing in reverse order is faster.\r
for (int parentIndex : parentIndices) {\r
TreeNode task = treeData.getDataAtIndex(parentIndex);\r
task.setExpanded(true);\r
- collapsed.remove(task);\r
+ expanded.add(task);\r
rowIndexes.addAll(getModel().expand(parentIndex));\r
}\r
\r
fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes));\r
}\r
\r
- public void expandAllRows() {\r
- Collection<Integer> parentIndices = getHiddenRowIndexes();\r
- List<Integer> rowIndexes = new ArrayList<Integer>();\r
- for (int parentIndex : parentIndices) {\r
- rowIndexes.addAll(getModel().expand(parentIndex));\r
- }\r
- for (TreeNode t : collapsed)\r
- t.setExpanded(true);\r
- collapsed.clear();\r
- getHiddenRowIndexes().clear();\r
- ((GETreeRowModel)getModel()).clear();\r
- invalidateCache();\r
- fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes));\r
- }\r
+// public void expandAllRows() {\r
+// Collection<Integer> parentIndices = getHiddenRowIndexes();\r
+// List<Integer> rowIndexes = new ArrayList<Integer>();\r
+// for (int parentIndex : parentIndices) {\r
+// rowIndexes.addAll(getModel().expand(parentIndex));\r
+// }\r
+// for (TreeNode t : collapsed)\r
+// t.setExpanded(true);\r
+// collapsed.clear();\r
+// getHiddenRowIndexes().clear();\r
+// ((GETreeRowModel)getModel()).clear();\r
+// invalidateCache();\r
+// fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes));\r
+// }\r
\r
@Override\r
protected void invalidateCache() {\r
hiddenPos.add(new int[]{0,0});\r
}\r
\r
+ private void _collapseAllRows() {\r
+ int count = treeData.getElementCount();\r
+ List <Integer> rowIndexes = new ArrayList<Integer>(count);\r
+ for (int i = 0; i < count; i++) {\r
+ TreeNode t = treeData.getDataAtIndex(i);\r
+ // we don't want to hide the roots of the tree\r
+ if (!treeData.isRoot(t)) { \r
+ rowIndexes.add(i);\r
+ \r
+ } \r
+ getModel().collapse(i);\r
+ \r
+ }\r
+ this.getHiddenRowIndexes().addAll(rowIndexes);\r
+ invalidateCache();\r
+ }\r
+ \r
@Override\r
public void handleLayerEvent(ILayerEvent event) {\r
// Currently sorting is implemented by sorting the underlaying list.\r
// Another option would use some sort of sorting layers, so that the original data is kept intact, and\r
// sorting layer would map the row indexes to sorted row positions.\r
\r
- // preserve collapsed nodes \r
+ // preserve expanded nodes \r
Set<TreeNode> coll = null;\r
+// int hiddenCount = 0;\r
if (event instanceof IStructuralChangeEvent) {\r
IStructuralChangeEvent structuralChangeEvent = (IStructuralChangeEvent) event;\r
if (structuralChangeEvent.isVerticalStructureChanged()) {\r
- // expand old indices\r
- ((GETreeRowModel)getModel()).clear();\r
+ // store old indices\r
+ internalRefresh = true;\r
+ ((GETreeRowModel<?>)getModel()).clear();\r
+// hiddenCount = getHiddenRowIndexes().size();\r
getHiddenRowIndexes().clear();\r
- coll = collapsed;\r
+ // store expanded nodes and clear disposed nodes.\r
+ coll = new HashSet<>();\r
+ for (TreeNode n : expanded)\r
+ if (!n.isDisposed())\r
+ coll.add(n);\r
+ expanded.clear();\r
+ expanded.addAll(coll);\r
+ // filter hidden nodes (nodes that have collapsed ancestors)\r
+ coll.clear();\r
+ for (TreeNode n : expanded)\r
+ if (!n.isHidden())\r
+ coll.add(n);\r
}\r
}\r
super.handleLayerEvent(event);\r
if (coll != null) {\r
- // collapse new indices\r
+ _collapseAllRows();\r
+ // expand new indices\r
int ind[] = new int[coll.size()];\r
Iterator<TreeNode> iter = coll.iterator();\r
for (int i = 0; i < ind.length; i++) {\r
ind[i] = treeData.indexOf(iter.next());\r
}\r
- collapseTreeRow(ind);\r
+ expandTreeRow(ind);\r
+// if (getHiddenRowIndexes().size() != hiddenCount) {\r
+// System.out.println(getHiddenRowIndexes().size() + " != " + hiddenCount);\r
+// ((GETreeRowModel<?>)getModel()).clear();\r
+// getHiddenRowIndexes().clear();\r
+// _collapseAllRows();\r
+// //collapseAll();\r
+// // expand new indices\r
+// iter = coll.iterator();\r
+// for (int i = 0; i < ind.length; i++) {\r
+// ind[i] = treeData.indexOf(iter.next());\r
+// }\r
+// expandTreeRow(ind);\r
+// }\r
+ internalRefresh = false;\r
}\r
}\r
\r
- public Set<TreeNode> getCollapsed() {\r
- return collapsed;\r
+ private boolean internalRefresh = false;\r
+ \r
+ public void fireLayerEvent(ILayerEvent event) {\r
+ if (!internalRefresh)\r
+ super.fireLayerEvent(event);\r
+ \r
+ }\r
+ \r
+ public Set<TreeNode> getExpanded() {\r
+ return expanded;\r
}\r
\r
List<int[]> hiddenPos;\r
public class GETreeRowModel<T> implements ITreeRowModel<T>{\r
//private final HashSet<Integer> parentIndexes = new HashSet<Integer>();\r
//private final TIntHashSet parentIndexes = new TIntHashSet(1000, 0.8f);\r
- private final IntOpenHashSet parentIndexes = new IntOpenHashSet();\r
+ private final IntOpenHashSet expandedIndexes = new IntOpenHashSet();\r
\r
private final Collection<ITreeRowModelListener> listeners = new HashSet<ITreeRowModelListener>();\r
\r
}\r
\r
public boolean isCollapsed(int index) {\r
- return this.parentIndexes.contains(index);\r
+ return !this.expandedIndexes.contains(index);\r
}\r
\r
public void clear() {\r
- this.parentIndexes.clear();\r
+ this.expandedIndexes.clear();\r
}\r
\r
@Override\r
\r
@Override\r
public List<Integer> collapse(int index) {\r
- this.parentIndexes.add(index);\r
+ this.expandedIndexes.remove(index);\r
notifyListeners();\r
- return getChildIndexes(index);\r
+ List<Integer> list = getChildIndexes(index);\r
+ //this.parentIndexes.addAll(list);\r
+ return list;\r
}\r
\r
\r
\r
@Override\r
public List<Integer> expand(int index) {\r
- this.parentIndexes.remove(index);\r
+ this.expandedIndexes.add(index);\r
notifyListeners();\r
List<Integer> children = getExpandedChildIndexes(index);\r
return children;\r
\r
@Override\r
public List<Integer> collapseAll() {\r
- // TODO Auto-generated method stub\r
return null;\r
}\r
\r
int index = this.treeData.indexOf(child);\r
if (index >= 0) {\r
result.add(index);\r
- if (!parentIndexes.contains(index))\r
+ if (expandedIndexes.contains(index))\r
result.addAll(getExpandedChildIndexes(index));\r
} else {\r
result.addAll(getExpandedChildIndexes(child));\r
int index = this.treeData.indexOf(child);\r
if (index >= 0) {\r
result.add(index);\r
- if (!parentIndexes.contains(index))\r
+ if (expandedIndexes.contains(index))\r
result.addAll(getExpandedChildIndexes(index));\r
} else {\r
result.addAll(getExpandedChildIndexes(child));\r
--- /dev/null
+package org.simantics.browsing.ui.nattable;\r
+\r
+import java.util.Collection;\r
+import java.util.List;\r
+import java.util.regex.Pattern;\r
+\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.nebula.widgets.nattable.NatTable;\r
+import org.eclipse.swt.events.KeyAdapter;\r
+import org.eclipse.swt.events.KeyEvent;\r
+import org.simantics.browsing.ui.GraphExplorer;\r
+import org.simantics.utils.ui.AdaptionUtils;\r
+\r
+/**\r
+ * Selects tree items based on pressed key events.<p>\r
+ * \r
+ * The default implementation of SWT.Tree (Windows?) uses only the the first column when matching the items.<p>\r
+ * \r
+ * This implementation checks all columns. Override <pre>matches(), matchesColumn()</pre> for customized behavior.<p>\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class KeyToSelectionAdapter extends KeyAdapter {\r
+\r
+ private static final int KEY_INPUT_DELAY = 500;\r
+ \r
+ private final NatTableGraphExplorer explorer;\r
+\r
+ private String matcher = "";\r
+ private int prevEvent = 0;\r
+ private int columns = 0;\r
+ \r
+ protected Pattern alphaNum;\r
+ \r
+ /**\r
+ * @param contextProvider\r
+ * @param explorer\r
+ */\r
+ public KeyToSelectionAdapter(GraphExplorer explorer) {\r
+ assert explorer != null;\r
+\r
+ this.explorer = (NatTableGraphExplorer)explorer;\r
+ this.alphaNum = Pattern.compile("\\p{Alnum}");\r
+ }\r
+\r
+ @Override\r
+ public void keyPressed(KeyEvent e) {\r
+ if (explorer.isDisposed())\r
+ return;\r
+\r
+ \r
+ if (!alphaNum.matcher(Character.toString(e.character)).matches())\r
+ return;\r
+ // concatenate / replace matcher.\r
+ if ((e.time - prevEvent) > KEY_INPUT_DELAY )\r
+ matcher = "";\r
+ prevEvent = e.time;\r
+ matcher = matcher += Character.toString(e.character);\r
+\r
+ \r
+ //TreeItem item = null;\r
+ NatTable tree = explorer.getControl();\r
+ columns = explorer.getColumns().length;\r
+ \r
+ IStructuredSelection sel = (IStructuredSelection)explorer.getWidgetSelection();\r
+ Collection<RowSelectionItem> selected = AdaptionUtils.adaptToCollection(sel, RowSelectionItem.class);\r
+ \r
+ \r
+ TreeNode item = find(tree, selected);\r
+ \r
+ if (item == null && matcher.length() > 1) {\r
+ matcher = matcher.substring(matcher.length()-1);\r
+ item = find(tree, selected);\r
+ }\r
+ \r
+ if (item != null) {\r
+ explorer.select(item);\r
+ explorer.show(item);\r
+// tree.select(item);\r
+// tree.showItem(item);\r
+ \r
+ \r
+ } \r
+ // without this the default handling would take over.\r
+ e.doit = false;\r
+ }\r
+ \r
+ private TreeNode previous = null;\r
+ private boolean foundPrev = false;\r
+ \r
+ private TreeNode find(NatTable tree, Collection<RowSelectionItem> selected) {\r
+ TreeNode item = null;\r
+\r
+ List<TreeNode> items = explorer.getItems();\r
+ \r
+ if (selected.size() == 0) {\r
+ previous = null;\r
+ foundPrev = true;\r
+ item = findItem(items);\r
+\r
+ } else {\r
+ previous = selected.iterator().next().item;\r
+ foundPrev = false;\r
+ item = findItem(items);\r
+ if (item == null) {\r
+ previous = null;\r
+ foundPrev = true;\r
+ item = findItem(items);\r
+ }\r
+ }\r
+ return item;\r
+ }\r
+ \r
+ private TreeNode findItem(List<TreeNode> items) {\r
+ for (int i = 0; i < items.size(); i++) {\r
+ TreeNode item = items.get(i);\r
+ if (item != previous) {\r
+ if (foundPrev && matches(item, columns, matcher))\r
+ return item;\r
+ \r
+ } else {\r
+ foundPrev = true;\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ \r
+ /**\r
+ * \r
+ * @param item\r
+ * @param depth Depth of the item in the tree.\r
+ * @param columns Number of columns.\r
+ * @param string Matching string.\r
+ * @return\r
+ */\r
+ protected boolean matches(TreeNode item, int columns, String matcher) {\r
+ for (int c = 0; c < columns; c++) { \r
+ if (matchesColumn(item, c, matcher)) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param item\r
+ * @param column\r
+ * @param matcher\r
+ * @return\r
+ */\r
+ protected boolean matchesColumn(TreeNode item, int column, String matcher) {\r
+ String text = item.getValueString(column);\r
+ if (text.toLowerCase().startsWith(matcher)) {\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+\r
+}\r
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
package org.simantics.browsing.ui.nattable;\r
\r
import java.util.ArrayList;\r
+import java.util.Collection;\r
import java.util.List;\r
\r
import org.eclipse.jface.viewers.IPostSelectionProvider;\r
import org.eclipse.swt.graphics.Point;\r
import org.eclipse.swt.widgets.Event;\r
import org.simantics.utils.datastructures.MapList;\r
+import org.simantics.utils.ui.AdaptionUtils;\r
\r
public class NatTableSelectionAdaptor implements ISelectionProvider, IPostSelectionProvider, ILayerListener {\r
NatTable natTable;\r
public void setSelection(ISelection selection) {\r
if (!(selection instanceof StructuredSelection))\r
throw new IllegalArgumentException("Selection must be structured selection");\r
+ if (selection.isEmpty()) {\r
+ selectionLayer.clear(false);\r
+ natTable.redraw();\r
+ return;\r
+ }\r
+ List<RowSelectionItem> rowItems = new ArrayList<>(AdaptionUtils.adaptToCollection(selection, RowSelectionItem.class));\r
+ if (rowItems.size() > 0) {\r
+ \r
+ setSelectionExternal(rowItems);\r
+ return;\r
+ }\r
+ Collection<TreeNode> nodes = AdaptionUtils.adaptToCollection(selection, TreeNode.class);\r
+ if (nodes.size() > 0) {\r
+ List<RowSelectionItem> selected = new ArrayList<>();\r
+ int allCols[] = new int[selectionLayer.getColumnCount()];\r
+ for (int i = 0; i < allCols.length; i++)\r
+ allCols[i] = i;\r
+ for (TreeNode n : nodes) {\r
+ selected.add(new RowSelectionItem(n, n.listIndex, allCols));\r
+ }\r
+ setSelectionExternal(selected);\r
+ return;\r
+ }\r
\r
}\r
\r
+ private void setSelectionExternal(List<RowSelectionItem> items) {\r
+ selectionLayer.clear(true);\r
+ for (RowSelectionItem item : items) {\r
+ for (int c : item.columnIndex)\r
+ selectionLayer.selectCell(c, item.rowIndex, false, true);\r
+ }\r
+ selection = new StructuredSelection(items);\r
+ fireEvents();\r
+ }\r
\r
\r
private List<Point> selectedCells = new ArrayList<Point>();\r
TreeNode parent;\r
List<TreeNode> children = new ArrayList<TreeNode>();\r
boolean expanded;\r
+ boolean autoExpanded = false;\r
\r
public TreeNode(NodeContext context, GeViewerContext explorerContext) {\r
this.context = context;\r
explorerContext.getContextToNodeMap().add(context, this);\r
}\r
\r
- int getDepth() {\r
+ public int getDepth() {\r
if (parent == null)\r
return 0;\r
return parent.getDepth() + 1;\r
}\r
\r
- int listIndex;\r
+ int listIndex = -1;\r
\r
public int getListIndex() {\r
return listIndex;\r
return expanded;\r
}\r
\r
+ public boolean isHidden() {\r
+ TreeNode n = parent;\r
+ while (n != null) {\r
+ if (!n.isExpanded())\r
+ return true;\r
+ n = n.getParent();\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ public TreeNode getCollapsedAncestor() {\r
+ TreeNode collapsed = null;\r
+ TreeNode n = parent;\r
+ while (n != null) {\r
+ if (!n.isExpanded())\r
+ collapsed = n;\r
+ n = n.getParent();\r
+ }\r
+ return collapsed;\r
+ }\r
+ \r
public NodeContext getContext() {\r
return context;\r
}\r
Map<String, String> runtimeLabels;\r
\r
public String getValueString(int column) {\r
- if (column == 0) {\r
+ if (column == 0)\r
initData();\r
- }\r
if (labeler != null) {\r
String key = explorerContext.getGe().getColumns()[column].getKey();\r
String s = null;\r
\r
}\r
\r
- private void initData() {\r
+ public void initData() {\r
labeler = manager.query(context, BuiltinKeys.SELECTED_LABELER);\r
imager = manager.query(context, BuiltinKeys.SELECTED_IMAGER);\r
labelDecorators = manager.query(context, BuiltinKeys.LABEL_DECORATORS);\r
\r
}\r
for (int i = oldCount; i < childContexts.length; i++) {\r
- addChild(childContexts[i], explorerContext);\r
+ Integer oldIndex = indexes.getLeft(i);\r
+ if (oldIndex == null) {\r
+ addChild(childContexts[i], explorerContext);\r
+ } else {\r
+ TreeNode n = oldChildren.get(oldIndex);\r
+ children.add(n);\r
+ }\r
}\r
} else {\r
for (int i = 0; i < childContexts.length; i++) {\r
\r
return context.getAdapter(adapter);\r
}\r
+ \r
+ @Override\r
+ public String toString() {\r
+ return "TreeNode: " + listIndex + " " + (expanded ? "(+)" : "(-)") + " " + context ;\r
+ }\r
\r
}\r
String extension = (String)t.get(1);\r
filterNames[index] = filterName;\r
extensions[index] = extension;\r
+ index++;\r
}\r
\r
dialog.setFilterExtensions(extensions);\r