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