]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/TreeNode.java
Sync git svn branch with SVN repository r33144.
[simantics/platform.git] / bundles / org.simantics.browsing.ui.nattable / src / org / simantics / browsing / ui / nattable / TreeNode.java
diff --git a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/TreeNode.java b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/TreeNode.java
new file mode 100644 (file)
index 0000000..941c6f3
--- /dev/null
@@ -0,0 +1,367 @@
+package org.simantics.browsing.ui.nattable;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.eclipse.jface.resource.ColorDescriptor;\r
+import org.eclipse.jface.resource.FontDescriptor;\r
+import org.eclipse.jface.resource.ImageDescriptor;\r
+import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes;\r
+import org.eclipse.nebula.widgets.nattable.style.Style;\r
+import org.eclipse.swt.graphics.Color;\r
+import org.eclipse.swt.graphics.Font;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.simantics.browsing.ui.BuiltinKeys;\r
+import org.simantics.browsing.ui.NodeContext;\r
+import org.simantics.browsing.ui.common.internal.GENodeQueryManager;\r
+import org.simantics.browsing.ui.content.ImageDecorator;\r
+import org.simantics.browsing.ui.content.Imager;\r
+import org.simantics.browsing.ui.content.LabelDecorator;\r
+import org.simantics.browsing.ui.content.Labeler;\r
+import org.simantics.browsing.ui.nattable.NatTableGraphExplorer.GECache2;\r
+import org.simantics.browsing.ui.nattable.NatTableGraphExplorer.GeViewerContext;\r
+import org.simantics.browsing.ui.swt.ViewerRowReference;\r
+import org.simantics.utils.datastructures.BijectionMap;\r
+\r
+public class TreeNode implements IAdaptable {\r
+       private static boolean DEBUG = false;\r
+       \r
+       private NodeContext context;\r
+       GENodeQueryManager manager;\r
+       GeViewerContext explorerContext;\r
+       \r
+       TreeNode parent;\r
+       List<TreeNode> children = new ArrayList<TreeNode>();\r
+       boolean expanded;\r
+       \r
+       public TreeNode(NodeContext context, GeViewerContext explorerContext) {\r
+               this.context = context;\r
+               this.explorerContext = explorerContext;\r
+               this.expanded = false;\r
+               manager = new GENodeQueryManager(explorerContext, null, null, ViewerRowReference.create(this));\r
+               explorerContext.getContextToNodeMap().add(context, this);\r
+       }\r
+       \r
+       int getDepth() {\r
+               if (parent == null)\r
+                       return 0;\r
+               return parent.getDepth() + 1;\r
+       }\r
+       \r
+       int listIndex;\r
+       \r
+       public int getListIndex() {\r
+               return listIndex;\r
+       }\r
+       \r
+       public void setListIndex(int listIndex) {\r
+               this.listIndex = listIndex;\r
+       }\r
+       \r
+       List<TreeNode> getChildren() {\r
+               return children;\r
+       }\r
+       \r
+       public TreeNode getParent() {\r
+               return parent;\r
+       }\r
+       \r
+       public void setExpanded(boolean expanded) {\r
+               this.expanded = expanded;\r
+       }\r
+       \r
+       public boolean isExpanded() {\r
+               return expanded;\r
+       }\r
+       \r
+       public NodeContext getContext() {\r
+               return context;\r
+       }\r
+       \r
+       private Labeler labeler;\r
+       private Imager imager;\r
+       Collection<LabelDecorator> labelDecorators;\r
+       Collection<ImageDecorator> imageDecorators;\r
+        \r
+       Map<String, String> labels;\r
+       Map<String, String> runtimeLabels;\r
+       \r
+       public String getValueString(int column) {\r
+               if (column == 0) {\r
+                       initData();\r
+               }\r
+               if (labeler != null) {\r
+                       String key = explorerContext.getGe().getColumns()[column].getKey();\r
+                       String s = null;\r
+                       if (runtimeLabels != null)\r
+                               s = runtimeLabels.get(key);\r
+                       if (s == null)\r
+                               s = labels.get(key);\r
+                       if (labelDecorators != null && !labelDecorators.isEmpty()) {\r
+                               int index = 0;\r
+                               for (LabelDecorator ld : labelDecorators) {\r
+                                       String ds = ld.decorateLabel(s, key, index);\r
+                                       if (ds != null)\r
+                                               s = ds;\r
+                               }\r
+                       }\r
+                       return s;\r
+               }\r
+               return null;\r
+       }\r
+       \r
+       public Image getImage(int column) {\r
+               String key = explorerContext.getGe().getColumns()[column].getKey();\r
+               if (imager != null) {\r
+                       Object descOrImage = null;\r
+                       boolean hasUncachedImages = false;\r
+\r
+                       ImageDescriptor desc = imager.getImage(key);\r
+                       if (desc != null) {\r
+                               int index = 0;\r
+                               // Attempt to decorate the label\r
+                               if (!imageDecorators.isEmpty()) {\r
+                                       for (ImageDecorator id : imageDecorators) {\r
+                                               ImageDescriptor ds = id.decorateImage(desc, key, index);\r
+                                               if (ds != null)\r
+                                                       desc = ds;\r
+                                       }\r
+                               }\r
+\r
+                               // Try resolving only cached images here and now\r
+                               Object img = explorerContext.getGe().localResourceManager.find(desc);\r
+                               if (img == null)\r
+                                       img = explorerContext.getGe().resourceManager.find(desc);\r
+\r
+                               descOrImage = img != null ? img : desc;\r
+                               hasUncachedImages |= img == null;\r
+                       }\r
+\r
+                       if (!hasUncachedImages) {\r
+                               return (Image) descOrImage;\r
+                       } else {\r
+                               // Schedule loading to another thread to refrain from\r
+                               // blocking\r
+                               // the UI with database operations.\r
+                               explorerContext.getGe().queueImageTask(this, new ImageTask(this, descOrImage));\r
+                               return null;\r
+                       }\r
+               } else {\r
+                       return null;\r
+               }\r
+       }\r
+       \r
+       public void getStyle(int column, Style style) {\r
+               String key = explorerContext.getGe().getColumns()[column].getKey();\r
+               FontDescriptor font = explorerContext.getGe().originalFont;\r
+               ColorDescriptor bg = explorerContext.getGe().originalBackground;\r
+               ColorDescriptor fg = explorerContext.getGe().originalForeground;\r
+               \r
+               // Attempt to decorate the label\r
+               if (labelDecorators != null && !labelDecorators.isEmpty()) {\r
+                       int index = 0;\r
+                       for (LabelDecorator ld : labelDecorators) {\r
+\r
+                               FontDescriptor dfont = ld.decorateFont(font, key, index);\r
+                               if (dfont != null)\r
+                                       font = dfont;\r
+\r
+                               ColorDescriptor dbg = ld.decorateBackground(bg, key, index);\r
+                               if (dbg != null)\r
+                                       bg = dbg;\r
+\r
+                               ColorDescriptor dfg = ld.decorateForeground(fg, key, index);\r
+                               if (dfg != null)\r
+                                       fg = dfg;\r
+                       }\r
+               }\r
+\r
+               if (font != explorerContext.getGe().originalFont) {\r
+                       // System.out.println("set font: " + index + ": " +\r
+                       // font);\r
+                       style.setAttributeValue(CellStyleAttributes.FONT,(Font) explorerContext.getGe().localResourceManager.get(font));\r
+               } else {\r
+                       style.setAttributeValue(CellStyleAttributes.FONT,(Font) (explorerContext.getGe().originalFont != null ? explorerContext.getGe().localResourceManager.get(explorerContext.getGe().originalFont) : null));\r
+               }\r
+               if (bg != explorerContext.getGe().originalBackground)\r
+                       style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR,(Color) explorerContext.getGe().localResourceManager.get(bg));\r
+               else\r
+                       style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR,(Color) (explorerContext.getGe().originalBackground != null ? explorerContext.getGe().localResourceManager.get(explorerContext.getGe().originalBackground) : null));\r
+               if (fg != explorerContext.getGe().originalForeground)\r
+                       style.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR,(Color) explorerContext.getGe().localResourceManager.get(fg));\r
+               else\r
+                       style.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR,(Color) (explorerContext.getGe().originalForeground != null ? explorerContext.getGe().localResourceManager.get(explorerContext.getGe().originalForeground) : null));\r
+\r
+       }\r
+       \r
+       private 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
+               imageDecorators = manager.query(context, BuiltinKeys.IMAGE_DECORATORS);\r
+               \r
+               if (labeler != null) {\r
+               labels = labeler.getLabels();\r
+                       runtimeLabels = labeler.getRuntimeLabels();\r
+       } else {\r
+               labels = null;\r
+               runtimeLabels = null;\r
+       }\r
+       }\r
+       \r
+       public TreeNode addChild(NodeContext context, GeViewerContext explorerContext) {\r
+               TreeNode child = new TreeNode(context, explorerContext);\r
+               child.parent = this;\r
+               children.add(child);\r
+               if (DEBUG) System.out.println("Add " + this  + " -> " + child);\r
+               return child;\r
+       }\r
+       \r
+       public TreeNode addChild(int index, NodeContext context,GeViewerContext explorerContext) {\r
+               \r
+               TreeNode child = new TreeNode(context, explorerContext);\r
+               child.parent = this;\r
+               children.add(index,child);\r
+               if (DEBUG) System.out.println("Add " + this  + " -> " + child + " at " + index);\r
+               return child;\r
+       }\r
+       \r
+       public TreeNode setChild(int index, NodeContext context, GeViewerContext explorerContext) {\r
+               \r
+               TreeNode child = new TreeNode(context, explorerContext);\r
+               child.parent = this;\r
+               children.set(index,child);\r
+               if (DEBUG) System.out.println("Set " + this  + " -> " + child + " at " + index);\r
+               return child;\r
+       }\r
+       \r
+       public void dispose() {\r
+               if (parent != null)\r
+                       parent.children.remove(this);\r
+               dispose2();\r
+       }\r
+       \r
+       public void dispose2() {\r
+               if (DEBUG)      System.out.println("dispose " + this);\r
+               parent = null;\r
+               for (TreeNode n : children) {\r
+                       n.dispose2();\r
+               }\r
+               clearCache();\r
+               children.clear();\r
+               explorerContext.getContextToNodeMap().remove(context, this);\r
+               context = null;\r
+               explorerContext = null;\r
+               manager.dispose();\r
+               manager = null; \r
+       }\r
+       \r
+       private void clearCache() {\r
+               if (explorerContext != null) {\r
+                       GECache2 cache = explorerContext.cache;\r
+                       \r
+                       if (cache != null) {\r
+                               cache.dispose(context);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public boolean updateChildren() {\r
+               if (context == null)\r
+                       throw new IllegalStateException("Node is disposed.");\r
+               \r
+               NodeContext[] childContexts = manager.query(context, BuiltinKeys.FINAL_CHILDREN);\r
+               \r
+               if (DEBUG) System.out.println("updateChildren " + childContexts.length + " " + this);\r
+               \r
+               \r
+               boolean modified = false;\r
+               synchronized (children) {\r
+                       \r
+                       int oldCount = children.size();\r
+                       BijectionMap<Integer, Integer> indexes = new BijectionMap<Integer, Integer>();\r
+                       Set<Integer> mapped = new HashSet<Integer>();\r
+                       boolean reorder = false;\r
+                       // locate matching pairs form old and new children\r
+                       for (int i = 0; i < oldCount; i++) {\r
+                               NodeContext oldCtx = children.get(i).context;\r
+                               for (int j = 0; j <childContexts.length; j++) {\r
+                                       if (mapped.contains(j))\r
+                                               continue;\r
+                                       if (oldCtx.equals(childContexts[j])) {\r
+                                               indexes.map(i, j);\r
+                                               mapped.add(j);\r
+                                               if (i != j)\r
+                                                       reorder = true;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+                       // update children if required\r
+                       if (childContexts.length != oldCount || reorder || childContexts.length != indexes.size()) {\r
+                               modified = true;\r
+                               List<TreeNode> oldChildren = new ArrayList<TreeNode>(oldCount);\r
+                               oldChildren.addAll(children);\r
+                               if (childContexts.length >= oldCount) {\r
+                       for (int i = 0; i < oldCount; i++) {\r
+                               Integer oldIndex = indexes.getLeft(i);\r
+                               if (oldIndex == null) {\r
+                                       setChild(i, childContexts[i], explorerContext);\r
+                               } else {\r
+                                       TreeNode n = oldChildren.get(oldIndex);\r
+                                       children.set(i, n);\r
+                               }\r
+                               \r
+                       }\r
+                       for (int i = oldCount; i < childContexts.length; i++) {\r
+                               addChild(childContexts[i], explorerContext);\r
+                       }\r
+                       } else {\r
+                               for (int i = 0; i < childContexts.length; i++) {\r
+                                       Integer oldIndex = indexes.getLeft(i);\r
+                               if (oldIndex == null) {\r
+                                       setChild(i, childContexts[i], explorerContext);\r
+                               } else {\r
+                                       TreeNode n = oldChildren.get(oldIndex);\r
+                                       children.set(i, n);\r
+                               }\r
+                       }\r
+                               for (int i = oldCount -1; i >= childContexts.length; i--) {\r
+                                       children.remove(i);\r
+                               }\r
+                       }\r
+                               for (int i = 0; i < oldChildren.size(); i++) {\r
+                                       if (!indexes.containsLeft(i)) {\r
+                                               oldChildren.get(i).dispose2();\r
+                                       }\r
+                               }\r
+                               \r
+                       }\r
+               \r
+               }\r
+               return modified;\r
+       }\r
+       \r
+       public boolean isDisposed() {\r
+               return context == null;\r
+       }\r
+       \r
+       public GENodeQueryManager getManager() {\r
+               return manager;\r
+       }\r
+       \r
+       @SuppressWarnings("rawtypes")\r
+       @Override\r
+       public Object getAdapter(Class adapter) {\r
+               if (adapter == NodeContext.class)\r
+                       return context;\r
+               \r
+               return context.getAdapter(adapter);\r
+       }\r
+\r
+}\r